php runtime and server environment
Fibers, Coroutines, And Non-Blocking I/O
Fibers let PHP pause a piece of code and resume it later. Async libraries can use fibers to make non-blocking code look more like normal sequential PHP.
The important point is that fibers are not magic parallel threads. A fiber only pauses and resumes execution. Non-blocking I/O still requires an event loop, compatible libraries, and operations that actually give control back while waiting.
A small fiber example
<?php
declare(strict_types=1);
$fiber = new Fiber(function (): string {
echo 'Fiber started' . PHP_EOL;
$value = Fiber::suspend('waiting');
echo 'Fiber resumed with ' . $value . PHP_EOL;
return 'done';
});
echo $fiber->start() . PHP_EOL;
echo $fiber->resume('data') . PHP_EOL;
// Prints:
// Fiber started
// waiting
// Fiber resumed with data
// done
The fiber starts, suspends with the value waiting, then resumes later with data.
Coroutines
A coroutine is a routine that can pause and continue later. In PHP conversations, "coroutine" is often used when talking about Swoole/OpenSwoole, Amp, or async-style code.
Different ecosystems use the word differently, so focus on the behaviour: code can yield control while waiting, then continue from the same point when the result is ready.
Non-blocking I/O
Blocking I/O waits until the operation finishes:
<?php
declare(strict_types=1);
$contents = file_get_contents(__FILE__);
echo is_string($contents) ? 'read complete' : 'read failed';
echo PHP_EOL;
// Prints:
// read complete
That is fine in many scripts. In an event loop, blocking reads, sleeps, HTTP calls, DNS lookups, and database calls can stop other tasks from progressing.
Non-blocking I/O means the operation can start, the process can do other work while waiting, and a callback, promise, awaitable, or coroutine resumes when the operation is ready.
Fibers do not make blocking code safe
Wrapping blocking code in a fiber does not make it non-blocking:
<?php
declare(strict_types=1);
$fiber = new Fiber(function (): void {
sleep(1);
echo 'Blocking work finished' . PHP_EOL;
});
$fiber->start();
echo 'After fiber' . PHP_EOL;
// Prints:
// Blocking work finished
// After fiber
The process still waits during sleep(1). The fiber did not move the work to another thread or make the operating system call non-blocking.
What async libraries add
Libraries such as Amp and ReactPHP provide the machinery around fibers or event loops:
- scheduling work
- waiting for sockets or timers
- representing future results
- handling cancellation and timeouts
- coordinating many I/O tasks
- surfacing errors from async operations
Swoole/OpenSwoole provide coroutine features through an extension and runtime support. The exact APIs differ, but the professional concern is the same: do not mix blocking libraries into code that expects non-blocking behaviour.
What you should be able to do
After this lesson, you should be able to explain what a fiber does, why fibers are not threads, how coroutine terminology relates to pausing and resuming work, and why non-blocking I/O requires compatible libraries rather than just different syntax.
Practice
Task: Demonstrate A Fiber
Create a small PHP script that demonstrates pausing and resuming a fiber.
Requirements
- Start a fiber.
- Suspend it with a value.
- Resume it with another value.
- Print the output in order.
- Add a short note explaining why this does not automatically make blocking I/O non-blocking.
Check your work
The script should run without installing an async framework. The explanation should distinguish fibers from event loops and threads.
Show solution
<?php
declare(strict_types=1);
$fiber = new Fiber(function (): string {
echo 'Inside fiber before suspend' . PHP_EOL;
$received = Fiber::suspend('value from suspend');
echo 'Inside fiber after resume: ' . $received . PHP_EOL;
return 'fiber return value';
});
echo $fiber->start() . PHP_EOL;
echo $fiber->resume('value from resume') . PHP_EOL;
// Prints:
// Inside fiber before suspend
// value from suspend
// Inside fiber after resume: value from resume
// fiber return value
The fiber pauses and resumes, but it does not create a second thread. If the code inside the fiber calls a blocking function, the process still waits. Non-blocking I/O needs an event loop and compatible I/O libraries, not only fiber syntax.