Home: Roshan Kc

← All posts

PHP · Async 8 min read

PHP Async in 2026: Fibers, Coroutines and the Road to Native Async

Direct answer: PHP can do async today, just not with built-in async/await syntax. Fibers (PHP 8.1) give the language pausable functions. ReactPHP and AMPHP build event loops on top of them in pure PHP, and Swoole provides coroutines through an extension. PHP 8.6 adds a native polling API (Io\Poll), and an RFC for engine-level concurrency is under discussion. For real-time apps, PHP is viable now. It just takes more deliberate choices than Node.js.

"PHP can't do async" is one of the most common reasons teams pick Node.js over PHP. It's half true. This post explains what exists today, what's coming, and how to decide. It's part of my PHP in 2026 series.

Why async is harder in PHP than in Node.js#

Node.js was built around one event loop from day one, so every database driver and HTTP client is non-blocking by default. PHP was built around one request per process. Its standard functions (file_get_contents(), PDO, sleep()) block, and decades of libraries assume they can.

So PHP async isn't only a syntax problem. Every I/O call has to cooperate with a scheduler, or it blocks everything else running in that process.

Fibers: the foundation (PHP 8.1)#

A fiber is a function that can pause itself and be resumed later, keeping its full call stack. Fibers aren't parallelism, and they don't do I/O by themselves. They're a building block that lets libraries write async code that looks synchronous:

$fiber = new Fiber(function (): string {
    $value = Fiber::suspend('waiting');   // pause here
    return "resumed with {$value}";
});

$status = $fiber->start();        // "waiting"
$fiber->resume('data');           // continues after suspend()

Application code rarely touches fibers directly. Their value is that libraries no longer need promise chains or generators everywhere.

The options today#

OptionHow it worksBest forTrade-off
ReactPHPPure-PHP event loop with promises. Long-established and widely used.Socket servers, workers, concurrent HTTP callsNeeds ReactPHP-compatible libraries for I/O
AMPHP (v3)Pure-PHP event loop built on fibers, so code reads like normal synchronous PHPConcurrent clients and servers without a C extensionSame ecosystem constraint: blocking libraries still block
SwooleC/C++ extension with coroutines and runtime hooks that make many standard functions non-blockingHigh-concurrency HTTP and WebSocket servers, parallel I/O in a request, Laravel OctaneAn extension to install and maintain, plus long-running-worker discipline
Queues and workersPush slow work to background jobs (Laravel Horizon, Symfony Messenger)Emails, exports, webhooks, anything users don't wait onNot real-time, but solves most "we need async" problems

The honest truth: most teams asking for async actually need queues. If the user doesn't wait for the result, put it in a job. Reach for an event loop when one request or connection genuinely needs to do several I/O operations at once, or hold thousands of connections open.

Concurrency inside a request#

With Laravel Octane on Swoole, independent lookups run in parallel instead of one after another:

[$user, $orders, $notifications] = Octane::concurrently([
    fn () => User::find($id),
    fn () => Order::recentFor($id),
    fn () => Notification::unreadCount($id),
]);

Three 20 ms queries take about 20 ms instead of 60 ms. We use this pattern on dashboards; the full setup is in how we use Octane + Swoole, and the runtime trade-offs are in PHP runtimes explained.

What's coming: native async in the engine#

  • PHP 8.6: Io\Poll. A native polling API over epoll, kqueue and friends. Event loops can stop relying on stream_select(), which scales poorly. It's a quiet but important foundation. See PHP 8.6 features.
  • RFC: Concurrency Support in the PHP Engine (under discussion). Extracted from the larger TrueAsync project, it proposes an engine-level coroutine core with a pluggable scheduler. With no scheduler loaded, PHP behaves exactly as it does today. It adds no new syntax; it's the plumbing that would let a standard async model exist across extensions.
  • No async/await keywords are on the table yet. If engine-level concurrency lands, syntax and standard-library integration would come in later RFCs.

My read: native async is a multi-release journey, not something to wait for. The tools that exist today are production-ready.

PHP vs Node.js for real-time work#

NeedPHP optionNode.js
Background jobsExcellent (Horizon, Messenger)Good (BullMQ etc.)
WebSockets for app notificationsGood: Laravel Reverb, SwooleExcellent
Parallel I/O in a requestGood with Swoole/Octane or AMPHPNative
Thousands of long-lived connectionsPossible with Swoole or ReactPHPNative strength
Collaborative editors, streaming-heavy appsWorkable, but against the grainUsually the better fit

That matches what we concluded in why we chose Laravel over Node.js: PHP for the product, and a dedicated real-time service where the product is mostly real-time.

Key takeaways#

  • PHP has no async/await, but fibers (8.1), ReactPHP, AMPHP and Swoole make async PHP production-ready today.
  • Most "we need async" problems are solved by queues. Use event loops when a request truly needs concurrent I/O.
  • PHP 8.6's Io\Poll and the engine-concurrency RFC are building the foundation for native async.
  • For heavily real-time products, Node.js is still the more natural fit. For most products, PHP plus a queue plus WebSockets is enough.

Sources#