Fibers in Practice (Revolt / Amp)
debt(d7/e5/b7/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate phpstan is the available tool but automated detection is explicitly marked 'no'. Mixing blocking I/O inside an event loop or leaked fibers from missing cancellations will not be flagged by phpstan automatically — these manifest as stalls or memory leaks only under load or in production, requiring careful review or runtime profiling to catch.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix suggests unifying on Revolt as the standard event loop foundation, but common_mistakes include mixing blocking I/O throughout a codebase and missing cancellations on futures across many call sites. Fixing these patterns requires identifying and refactoring every blocking call and every long-running future in the async code paths, spanning multiple files within the async component.
Closest to 'strong gravitational pull' (d7). Applies_to is limited to cli and queue-worker contexts (not all PHP), but within those contexts the event loop choice is deeply load-bearing — every async library integration, I/O call pattern, fiber lifecycle decision, and cancellation strategy is shaped by the Revolt model. Mixing ecosystems or changing the concurrency model later would require significant rework of all async code.
Closest to 'serious trap' (t7). The misconception field explicitly states developers believe Revolt makes PHP truly asynchronous like Node.js with parallel execution, when in fact it is single-threaded cooperative concurrency. This contradicts mental models from Node.js, Go, or other async runtimes where I/O truly overlaps. The 'obvious' assumption of parallelism leads directly to race-condition-free but also performance-incorrect code, and blocking calls silently stall the entire loop — a documented but widely misunderstood gotcha.
Also Known As
TL;DR
Explanation
PHP 8.1 Fibers provide cooperative concurrency — a Fiber can suspend itself and be resumed, letting an event loop interleave multiple I/O-bound tasks without OS threads. Revolt (successor to ReactPHP's event loop) and Amp v3 build on Fibers to provide async HTTP clients, database drivers, and file I/O. Unlike promise chains, Fiber-based code reads top-to-bottom like synchronous code. Ideal for PHP CLI services, queue workers, and real-time applications with many concurrent connections. For highest throughput, evaluate Swoole or RoadRunner which use multi-threading rather than cooperative multitasking.
Common Misconception
Why It Matters
Common Mistakes
- Mixing blocking I/O calls inside a Revolt event loop — one blocking call stalls the entire loop.
- Not using cancellations on long-running futures — leaked fibers hold memory indefinitely.
- Expecting parallelism — Revolt is single-threaded cooperative concurrency, not multi-threading.
- Using Revolt for simple scripts where a synchronous approach is clearer and sufficient.
Code Examples
// Blocking call inside async context — stalls the event loop:
Revolut\EventLoop\run(function(): void {
$data = file_get_contents('https://api.example.com'); // Blocks!
echo $data;
});
// Use amphp/http-client or ReactPHP HTTP client instead
// Revolt event loop — cooperative concurrency (PHP 8.1+)
use Revolt\EventLoop;
EventLoop::delay(1.0, function(): void {
echo "Fires after 1 second\n";
});
EventLoop::repeat(0.5, function(): void {
echo "Fires every 500ms\n";
});
// Amp v3 — Fiber-based async I/O
use Amp\async;
use Amp\Future;
$a = async(fn() => slowOperation());
$b = async(fn() => anotherOperation());
[$resultA, $resultB] = Future\await([$a, $b]); // concurrent
EventLoop::run();