You have a loop of 10 API calls each taking 3 seconds? In classic PHP you wait 30 seconds. With PHP 8.1 Fibers you can run them in just 3 seconds — without installing a framework. It sounds like magic, but it's just native async programming built into the language.
We at Meteora Web have been developing in PHP for years, on custom platforms and WordPress. Fibers are one of those features that change how you think: they let you write async code without adopting ReactPHP, Amp, or any other ecosystem. In this guide we explain how they work and how to use them right now, with ready-to-run examples.
What Are Fibers and Why Are They Useful in PHP 8.1?
A Fiber is a cooperative execution unit that can suspend and resume where it left off. Unlike threads, Fibers share the same process and memory: there is no true parallelism, but synchronous concurrency controlled by the programmer.
The benefit is immediate: while waiting for a database response or an API call, instead of blocking the entire script, you suspend the Fiber and let other code run. As soon as the response arrives, you resume the Fiber from exactly where it stopped.
Before PHP 8.1, to get similar behavior you had to use generators (yield) or external libraries. Fibers offer a cleaner, more flexible API with full call stack preservation and exception handling.
The Difference Between Fiber, Generator, and Thread
Think of it this way:
Sponsored Protocol
- Generator: can suspend and return a value, but cannot be resumed from outside except by iteration. It cannot receive data when resumed.
- Thread (via
pthreadsorparallel): runs code in real parallel on multiple cores, but is heavy, complex, and unsupported on shared hosting. - Fiber: suspends and resumes from another point in the code with bidirectional data exchange. Uses a single thread, so it's lightweight and safe for I/O-bound operations.
For SMEs managing sites with many external requests (e.g., an e-commerce store querying multiple suppliers), Fibers are the right choice: zero dependencies, minimal overhead, multiplied performance.
How Do Fibers Work Compared to Traditional Coroutines?
A Fiber is created with new Fiber(callback). The callback contains the code to execute. To start it, call $fiber->start(). Inside the callback, call Fiber::suspend($value) to suspend and return a value to the caller. From outside, call $fiber->resume($data) to resume execution, passing a value back to the suspension point.
The key difference from generators and classic coroutines: the call stack is preserved. If inside the Fiber you have nested functions, an exception thrown deep inside can be caught by the caller without issues. With generators you had to manually propagate.
$fiber = new Fiber(function (): void {
echo "Fiber start\n";
$val = Fiber::suspend('first stop');
echo "Resumed with: $val\n";
});
$result = $fiber->start();
echo $result; // 'first stop'
$fiber->resume('hello'); // prints "Resumed with: hello"
Important: a Fiber does not run code in the background. It's a flow-control construct. The real power comes when you combine it with a scheduler that decides which Fibers to activate based on async events (e.g., non-blocking sockets, timers). But even without a scheduler, you can already use Fibers to write more readable code that would otherwise be a callback mess.
Sponsored Protocol
How to Build a Simple Async Scheduler with Fibers?
A scheduler is the heart of async programming. It manages a queue of active Fibers and resumes them when an event occurs. Here's a minimal example to run multiple tasks that simulate I/O operations (variable wait times).
class SimpleScheduler {
private array $tasks = [];
public function add(callable $task): void {
$this->tasks[] = new Fiber($task);
}
public function run(): void {
while (!empty($this->tasks)) {
foreach ($this->tasks as $key => $fiber) {
if ($fiber->isStarted() === false) {
$fiber->start();
} elseif ($fiber->isTerminated() === false) {
$fiber->resume();
} else {
unset($this->tasks[$key]);
}
}
}
}
}
$scheduler = new SimpleScheduler();
$scheduler->add(function () {
echo "Task 1 start\n";
Fiber::suspend();
echo "Task 1 end\n";
});
$scheduler->add(function () {
echo "Task 2 start\n";
Fiber::suspend();
echo "Task 2 end\n";
});
$scheduler->run();
// Output: Task 1 start, Task 2 start, Task 1 end, Task 2 end
Of course this is a trivial scheduler (round-robin without priorities). In a real scenario you'd want to resume Fibers only when data is ready (e.g., using stream_select or curl_multi_select). Still, it demonstrates the principle: multiple tasks make progress without waiting for each other.
Sponsored Protocol
Practical Example: Fetching Multiple URLs in Parallel
With a real scheduler based on curl_multi and Fibers you could write:
function fetchUrlAsync(string $url): string {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
// ... curl_multi setup ...
// Suspend the Fiber until the response is ready
$data = Fiber::suspend($ch);
return $data;
}
// Usage
$fiber = new Fiber(function () {
$result = fetchUrlAsync('https://api.example.com/data');
echo $result;
});
$fiber->start();
// ... event loop management that resumes when curl completes
Libraries like Revolt provide a ready-made event loop, but if you want to stay completely framework-free you can implement one in a few hundred lines. At Meteora Web we often prefer integrating Revolt because it's lightweight and doesn't impose a full-stack framework.
Sponsored Protocol
What Are the Limitations of Fibers and When to Use (or Avoid) Them?
Fibers are not a silver bullet. Here are the points to know before using them in production:
- No CPU-bound parallelism: if your code does heavy computations, Fibers won't speed anything up. For that you need extensions like
parallelor separate processes. - Need an event loop for async I/O: Fibers alone don't magically make I/O functions non-blocking (file, database, sockets). You must use non-blocking versions or wrappers like
ext-uv,ext-ev. - Scheduler overhead: if you manage hundreds of Fibers, scheduler performance becomes critical.
- Compatibility with legacy code: functions using
sleep(), blockingfile_get_contents(), or extensions not designed for async break the model. You need to replace them.
Where do they shine? Parallel I/O-bound operations: API calls, multiple database queries, scraping, remote file processing. If your app makes many HTTP requests, Fibers can cut response times from minutes to seconds.
How to Integrate Fibers into an Existing PHP Project Without a Framework?
If you have an application developed without a framework (or with a lightweight one), you can introduce Fibers gradually:
- Identify bottlenecks: sequential network or I/O operations.
- Rewrite those functions to use
Fiber::suspend()and a mini-scheduler. - Ensure all functions called inside the Fiber are non-blocking (or use wrappers like
curl_multi). - Test carefully: unhandled exceptions inside a Fiber can be tricky to debug.
A common pattern is to create a FiberPool that manages a fixed number of concurrent Fibers, limiting load. We've used it to parallelize transactional email sending and aggregate data from multiple marketplaces into a single dashboard.
Sponsored Protocol
Adoption Checklist
- PHP 8.1 or higher
- Event loop (Revolt, Amp, or custom)
- Non-blocking I/O extensions (curl_multi, sockets, ext-uv optional)
- Centralized exception handling in Fibers
- Memory usage monitoring (each Fiber retains its entire stack)
What to Do Next
Don't wait for the perfect framework. Fibers are already in your PHP. Here are three concrete actions to start today:
- Open a terminal and test the example with
php -r '...'(use the simple scheduler code above). - Identify a repetitive task in your project (e.g., polling 3 APIs every minute) and try rewriting it with Fibers.
- Read the official documentation on Fibers: PHP Manual – Fibers.
At Meteora Web we use Fibers in our Laravel/Livewire projects to manage lightweight async operation queues, and we've also introduced them in WordPress plugins for product synchronization with external warehouses. If you want to dive deeper, explore the entire PHP 8 advanced ecosystem in our Pillar on Advanced PHP 8.