For years, PHP’s main selling point was “boring, reliable, synchronous.” If you needed async backend services, you reached for Node.js, Go, or sometimes Python. But PHP 8.3 has quietly changed the math. With Fibers stabilized and the Revolt event loop powering a new generation of non-blocking libraries, PHP 8.3 is now a hidden gem for async backend services—not as a Node.js replacement, but as a pragmatic option for teams who want real concurrency without abandoning PHP. In this article, we’ll look at how Fibers work, what Revolt brings to the table, and a practical pattern you can apply today.
The old PHP problem: everything waits
Traditional PHP execution is simple: a request comes in, PHP runs top to bottom, and every I/O operation—a database query, an HTTP call, a Redis read—blocks the process until the response returns. In a classic PHP-FPM setup, this is acceptable because the web server spawns multiple processes to handle requests in parallel. But it falls apart when a single process needs to handle multiple concurrent operations, like a WebSocket server, a queue worker, or a microservice that fans out requests to third-party APIs.
Before Fibers, the workarounds were ugly:
- Message queues and job workers to fake parallelism.
- Callback-based async libraries that led to callback hell.
- Switching entirely to a non-PHP runtime for certain services.
Fibers: cooperative concurrency, not threading
Fibers arrived in PHP 8.1, but it took the ecosystem time to catch up. By PHP 8.3, they are a stable and mature tool—and they are not threads. A Fiber is a cooperative concurrency primitive. It runs on the main thread, yields control, and can be resumed later. Think of it as a function that can pause itself, hand the thread back to the caller, and later pick up exactly where it left off.
What does that give you? The ability to write code that looks synchronous but behaves asynchronously:
// A fiber that yields when waiting for I/O
$fiber = new Fiber(function () {
$response = $httpClient->get('https://api.example.com/data');
return json_decode($response, true);
});
The key insight is that Fibers alone don’t provide an event loop. Something has to decide which fiber gets to run and when to resume a paused fiber. That’s where Revolt comes in.
Revolt: the event loop under the hood
Revolt is a framework-agnostic event loop for PHP, developed by the team behind Amp. If you’ve used Amp v3, you’ve used Revolt. If you’ve used any modern PHP async library—such as amphp/http-client, amphp/amqp, or amphp/postgres—it runs on Revolt.
What makes Revolt essential is that it fills the gap between Fibers and practical concurrency. The event loop manages I/O streams, timers, signals, and deferred callbacks. When a Fiber suspends itself waiting for I/O, Revolt registers that I/O and lets other fibers run. When the I/O completes, Revolt resumes the suspended Fiber. The result is a cooperative scheduler that can handle thousands of concurrent I/O operations in a single process.
Because Revolt is designed as a shared foundation, multiple libraries can cooperate instead of each implementing its own loop. That’s a huge win for ecosystem interoperability.
Why PHP 8.3 matters now
PHP 8.3 was released in late 2023, but the current year is when this stack quietly becomes production-relevant. Here’s why the timing is right:
- Mature tooling: Amp v3 and Revolt have been battle-tested in production for years. Stability issues that plagued early adopters are solved.
- Fiber-aware drivers: Modern PHP drivers for PostgreSQL, MySQL, and Redis integrate naturally with event loops, reducing the need for opaque extensions like Swoole in many cases.
- Better memory footprint: A single PHP process running an event loop with fibers can handle many concurrent connections, dramatically reducing memory compared to the process-per-request model.
- Healthy open source ecosystem: The tools around Revolt—including testing utilities and observability integrations—have matured to the point where production adoption is straightforward.
The result: you can build async backend services in PHP 8.3 without fighting the language. It’s not the flashiest approach, but it is quietly effective.
A practical pattern: concurrent API calls with Amp and Revolt
The most common use case for async PHP is performing multiple I/O operations at the same time. Here’s a real pattern using Amp\async() and Amp\await(), both running on the Revolt event loop:
use function Amp\async;
use function Amp\await;
$first = async(function () {
return $http->request('https://api.one.example/data');
});
$second = async(function () {
return $http->request('https://api.two.example/data');
});
$result1 = await($first);
$result2 = await($second);
What’s happening here?
async()creates a Fiber and starts it. The Fiber begins making the HTTP request.- When the Fiber hits the blocking I/O call, it suspends. Revolt takes over, watching the underlying network socket.
- Both requests progress concurrently in the same thread.
await()blocks until each Fiber completes, giving you the result in order.
You get the simplicity of sequential code with the performance of non-blocking I/O. No callbacks, no promise chains, no complicated state machines.
Where this fits in real services
This pattern shines in API gateways, backend-for-frontend layers, and data aggregation services. Imagine a service that must fetch user data, order history, and inventory status from three separate services before rendering an app screen. In synchronous PHP, that’s three sequential round trips: 300ms total if each takes 100ms. With Fibers and Revolt, they run in parallel, and total latency drops to roughly 100ms. That’s a 3x improvement on a single critical path.
Caveats: Fibers are not a free lunch
It’s worth being candid about the limitations. Fibers and Revolt don’t make CPU-bound work faster—this is I/O concurrency, not parallelism. If you need to crunch large data sets or run heavy algorithms, a different runtime or architecture is still the right answer.
You also need to be deliberate about your event loop. If you use a traditional blocking function inside a Fiber—for example, the built-in file_get_contents() on a remote URL—it will block the entire loop, not just the Fiber. Guzzle and similar libraries have async support, but plain blocking calls undercut the benefit.
Finally, familiarity matters. Your team needs to understand cooperative scheduling and the discipline of never blocking the loop. In exchange, you get a production-proven concurrency model without adding another language to your stack.
A hidden gem worth adopting
For teams already invested in PHP, the answer is increasingly yes. You don’t have to migrate your whole platform to Node.js to get non-blocking behavior at the service boundary. PHP 8.3, with Fibers as the language primitive and Revolt as the event-loop backbone, gives you a coherent way to write concurrent backend services.
It’s not hyped and it’s not flashy, but it works. In a world where backend engineers chase ever-shifting trends, PHP’s async story offers something rarer: a practical, incremental path that fits the language you already know.
PHP 8.3 with Fibers and Revolt provides a pragmatic route to async backend services, addressing the I/O bottleneck that once pushed PHP teams toward other runtimes. The ecosystem has matured, the patterns are clear, and the performance gains are real. For PHP shops looking to build faster services without leaving the language, it’s a hidden gem that deserves a closer look.
