Fibers arrived in PHP 8.1 as a cooperative multitasking mechanism – the ability to suspend and resume a function at any point. These are not threads or processes – a Fiber runs in the same PHP thread but allows switching between tasks without blocking. I show how Fibers work, where they make sense, and how async libraries (ReactPHP, Amp) use them under the hood.
What is a Fiber
A Fiber is a function that can be suspended (Fiber::suspend()) and resumed ($fiber->resume()). Unlike a regular function: it does not have to run to completion before control returns to the caller. Unlike a generator: a Fiber can receive values on resume and return values on suspend in both directions.
<?php
declare(strict_types=1);
$fiber = new Fiber(function(): string {
echo "Fiber: start\n";
$value = Fiber::suspend('first pause');
echo "Fiber: resumed with value: {$value}\n";
$value2 = Fiber::suspend('second pause');
echo "Fiber: resumed again: {$value2}\n";
return 'fiber finished';
});
$result1 = $fiber->start();
echo "Main code received: {$result1}\n"; // "first pause"
$result2 = $fiber->resume('data 1');
echo "Main code received: {$result2}\n"; // "second pause"
$fiber->resume('data 2');
echo "Fiber return: " . $fiber->getReturn() . "\n";
// Output:
// Fiber: start
// Main code received: first pause
// Fiber: resumed with value: data 1
// Main code received: second pause
// Fiber: resumed again: data 2
// Fiber return: fiber finished
Scheduler – switching between Fibers
<?php
declare(strict_types=1);
class FiberScheduler
{
/** @var Fiber[] */
private array $fibers = [];
private array $queue = [];
public function add(Fiber $fiber): void
{
$this->fibers[] = $fiber;
$this->queue[] = $fiber;
}
public function run(): void
{
foreach ($this->fibers as $fiber) {
$fiber->start();
}
while (!empty($this->queue)) {
$fiber = array_shift($this->queue);
if ($fiber->isSuspended()) {
$fiber->resume();
if ($fiber->isSuspended()) {
$this->queue[] = $fiber;
}
}
}
}
}
function fetchData(string $url, int $delay): string
{
echo "Fetching {$url}...\n";
Fiber::suspend();
for ($i = 0; $i < $delay; $i++) {
Fiber::suspend();
}
return "data from {$url}";
}
$scheduler = new FiberScheduler();
$scheduler->add(new Fiber(function() {
$result = fetchData('https://api.example.com/orders', 2);
echo "Done: {$result}\n";
}));
$scheduler->add(new Fiber(function() {
$result = fetchData('https://api.example.com/products', 1);
echo "Done: {$result}\n";
}));
$scheduler->run();
// products finishes before orders (smaller delay)
Fibers in ReactPHP
<?php
require 'vendor/autoload.php';
use React\Http\Browser;
// New style (Fiber-based, ReactPHP 3+)
// Looks synchronous, runs asynchronously
React\Async\async(function() {
$browser = new Browser();
$response1 = React\Async\await($browser->get('https://httpbin.org/get'));
$response2 = React\Async\await($browser->get('https://httpbin.org/post'));
echo strlen((string)$response1->getBody()) . "\n";
echo strlen((string)$response2->getBody()) . "\n";
})();
Fibers vs Generators vs Promises
| Mechanism | Suspension | Communication | Use case |
|---|---|---|---|
| Generator | yield | One-way (yield value) | Iteration, lazy sequences |
| Fiber | Fiber::suspend() | Two-way (suspend/resume) | Cooperative multitasking |
| Promise | then/catch | Callback-based | Async API calls |
| async/await | await (over Fiber) | Synchronous style | Readable async code |
Practical use – batch processor
<?php
declare(strict_types=1);
class BatchProcessor
{
public function process(array $items, callable $handler, int $concurrency = 5): array
{
$results = [];
$chunks = array_chunk($items, $concurrency);
foreach ($chunks as $chunk) {
$fibers = [];
foreach ($chunk as $key => $item) {
$fiber = new Fiber(function() use ($item, $handler, $key, &$results) {
$results[$key] = $handler($item);
});
$fibers[] = $fiber;
$fiber->start();
}
$running = true;
while ($running) {
$running = false;
foreach ($fibers as $fiber) {
if ($fiber->isSuspended()) {
$fiber->resume();
$running = true;
}
}
}
}
return $results;
}
}
$processor = new BatchProcessor();
$results = $processor->process(range(1, 100), function(int $item): int {
Fiber::suspend();
return $item * 2;
}, concurrency: 10);
echo count($results) . " results processed\n";
Summary
Fibers are a low-level cooperative multitasking mechanism in PHP. They do not replace threads or processes – they run in a single thread. Their real power comes through higher-level libraries: ReactPHP, Amp, Revolt. Direct use of Fibers is rare – more often you write code using async/await from these libraries, which manage Fibers internally. In the context of Magento 2, Fibers can be useful in CLI scripts for parallel processing of large data collections.
