← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

PHP Fibers — Internals & Scheduler Patterns

php PHP 8.1+ Advanced

Also Known As

fibers internals PHP coroutines stackful coroutines cooperative multitasking PHP

TL;DR

How PHP Fibers work under the hood — stack allocation, suspension mechanics, and how to build a cooperative multitasking scheduler on top of the Fiber API introduced in PHP 8.1.

Explanation

A PHP Fiber is a stackful coroutine — it gets its own call stack (unlike generators which resume from a single yield point). Internally, the Zend Engine allocates a separate C stack for each fiber (configurable via `fiber.stack_size` in php.ini, default 2MB) and saves/restores CPU registers and the stack pointer on suspend/resume. `Fiber::suspend($value)` saves the current stack frame, returns control to the caller, and passes `$value` out. `$fiber->resume($value)` restores the stack frame and passes `$value` back in as the return value of `Fiber::suspend()`. Unlike threads, fibers are cooperative — only one fiber runs at a time, switching only at explicit `Fiber::suspend()` calls, so no mutexes are needed for shared state. A scheduler is a loop that tracks pending fibers and resumes them when their awaited condition is met (I/O ready, timer elapsed). Libraries like ReactPHP and Revolt PHP use fibers to implement `async/await`-style concurrency on top of an event loop.

Diagram

sequenceDiagram
    participant S as Scheduler
    participant FA as Fiber A
    participant FB as Fiber B
    S->>FA: start()
    FA->>FA: step 1
    FA->>S: Fiber::suspend()
    S->>FB: start()
    FB->>FB: step 1
    FB->>S: Fiber::suspend()
    S->>FA: resume()
    FA->>FA: step 2
    FA->>S: terminated
    S->>FB: resume()
    FB->>FB: step 2
    FB->>S: terminated

Common Misconception

PHP Fibers enable true parallel execution — Fibers are cooperative, single-threaded concurrency. Only one fiber runs at a time; they interleave by voluntarily suspending, not by running on separate CPU cores. For true parallelism use `parallel` extension or separate processes.

Why It Matters

Fibers are the foundation of async PHP — frameworks like Revolt, ReactPHP 3+, and Amp v3 use them to write I/O-concurrent code that reads like synchronous PHP but suspends at I/O boundaries. Understanding fibers lets you debug async PHP code, tune stack size, and build lightweight schedulers for CLI tools.

Common Mistakes

  • Not handling exceptions thrown into a fiber — `$fiber->throw(new Exception)` resumes the fiber with an exception at the suspend point; uncaught, it propagates to the caller.
  • Blocking inside a fiber (sleep(), PDO query without async driver) — blocks the entire PHP process, defeating the purpose of cooperative concurrency.
  • Creating thousands of fibers simultaneously — each fiber allocates a full stack (default 2MB); 1000 fibers = 2GB RAM. Pool and reuse fibers for high-concurrency workloads.
  • Calling `Fiber::suspend()` outside a fiber — throws a `FiberError`; always check `Fiber::getCurrent() !== null`.

Code Examples

💡 Note
The scheduler round-robins between fibers — each runs until it suspends, then the next gets a turn, showing cooperative interleaving without threads.
✗ Vulnerable
// Blocking inside a fiber — defeats cooperative concurrency:
$fiber = new Fiber(function(): void {
    sleep(2);           // blocks entire process — no other fiber runs
    $result = file_get_contents('https://example.com'); // blocking I/O
    Fiber::suspend($result);
});
$fiber->start();
✓ Fixed
// Simple cooperative scheduler using Fibers + non-blocking I/O:
class Scheduler {
    private array $fibers = [];

    public function add(Fiber $fiber): void {
        $this->fibers[] = $fiber;
    }

    public function run(): void {
        while ($this->fibers) {
            foreach ($this->fibers as $key => $fiber) {
                if (!$fiber->isStarted()) $fiber->start();
                elseif ($fiber->isSuspended()) $fiber->resume();

                if ($fiber->isTerminated()) {
                    unset($this->fibers[$key]);
                }
            }
        }
    }
}

$scheduler = new Scheduler();
$scheduler->add(new Fiber(function(): void {
    echo "Task A: step 1\n";
    Fiber::suspend(); // yield control
    echo "Task A: step 2\n";
}));
$scheduler->add(new Fiber(function(): void {
    echo "Task B: step 1\n";
    Fiber::suspend();
    echo "Task B: step 2\n";
}));
$scheduler->run();
// Output: Task A: step 1 / Task B: step 1 / Task A: step 2 / Task B: step 2

Added 24 Mar 2026
Views 32
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 3 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 3 pings S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 3 pings S 1 ping S 0 pings M 0 pings T 0 pings W 1 ping T
No pings yesterday
ChatGPT 7 Perplexity 7 Amazonbot 6 Google 4 Unknown AI 3 Meta AI 1 Ahrefs 1
crawler 27 crawler_json 2
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: High
⚡ Quick Fix
Never call blocking functions (sleep, PDO, file_get_contents) inside a fiber — use non-blocking async equivalents from Revolt or ReactPHP
📦 Applies To
PHP 8.1+ cli queue-worker Revolt ReactPHP Amp
🔗 Prerequisites
🔍 Detection Hints
sleep() or blocking I/O calls inside a Fiber callback; new Fiber() in a loop without pooling
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: High Context: Function Tests: Update

✓ schema.org compliant