PHP 8.1 introduced Fibers — a low-level cooperative concurrency primitive that lets you pause execution of a function, yield control back to the caller, and resume later. While PHP remains single-threaded, Fibers unlock patterns like async I/O coordination, coroutine-style generators, and lightweight task queues that were previously impossible without forking or external queues.
Problem: WordPress background processing — sending emails, generating reports, syncing with external APIs — runs synchronously in PHP or through WP-Cron, blocking the response or missing execution windows on low-traffic sites.
Solution: Use PHP Fibers (PHP 8.1+) to implement cooperative concurrency within a single request: start a Fiber for each background task, suspend with Fiber::suspend() at I/O boundaries, and resume them in turn from the event loop. For truly async processing, combine with a queue system (Redis List + a dedicated worker process running a PHP Fiber scheduler).
The examples below show the basic Fiber API, a coroutine-style pipeline that interleaves three tasks, and a practical WordPress pattern for processing batches of posts inside a Fiber to avoid timeout issues in long-running admin actions.
<?php
// ── 1. Basic Fiber API ────────────────────────────────────────────────────
$fiber = new Fiber( function (): void {
$value = Fiber::suspend( 'first' ); // pause; send 'first' to caller
echo "Resumed with: $value\n"; // caller sends 'hello' back
Fiber::suspend( 'second' );
echo "Fiber finished\n";
} );
$first = $fiber->start(); // 'first'
$second = $fiber->resume( 'hello' ); // 'second'
$fiber->resume(); // fiber finishes
// ── 2. Coroutine-style task runner ────────────────────────────────────────
function makeTask( string $name, int $steps ): Fiber {
return new Fiber( function () use ( $name, $steps ): void {
for ( $i = 1; $i <= $steps; $i++ ) {
echo "$name step $i\n";
Fiber::suspend(); // yield to the scheduler
}
} );
}
$tasks = [
makeTask( 'A', 3 ),
makeTask( 'B', 2 ),
makeTask( 'C', 4 ),
];
// Start all tasks
foreach ( $tasks as $t ) { $t->start(); }
// Round-robin until all are done
$running = true;
while ( $running ) {
$running = false;
foreach ( $tasks as $t ) {
if ( ! $t->isTerminated() ) {
$t->resume();
$running = true;
}
}
}
// ── 3. WordPress: batch-process posts without timing out ─────────────────
add_action( 'wp_ajax_reindex_posts', function () {
check_ajax_referer( 'reindex_nonce', 'nonce' );
$ids = get_posts( [ 'fields' => 'ids', 'numberposts' => -1 ] );
$fiber = new Fiber( function () use ( $ids ): void {
$batch = [];
foreach ( $ids as $id ) {
$batch[] = $id;
if ( count( $batch ) === 50 ) {
process_batch( $batch ); // custom indexing function
$batch = [];
Fiber::suspend( count( $batch ) ); // yield progress
}
}
if ( $batch ) {
process_batch( $batch );
}
} );
$fiber->start();
while ( ! $fiber->isTerminated() ) {
$fiber->resume();
// Optionally: echo progress to client via ob_flush() / flush()
}
wp_send_json_success( [ 'indexed' => count( $ids ) ] );
} );
NOTE: Fibers do not add true parallelism — they are cooperative, meaning only one fiber runs at a time; their value is structured control flow and the ability to integrate with event-loop libraries like ReactPHP or Revolt, not raw CPU parallelism.