Can PHP Achieve True Asynchronous Execution? Inside the True Async RFC
This article examines the PHP True Async RFC, outlining its goals to provide a standard C‑API for non‑blocking I/O, describing implicit versus explicit async models, presenting a scheduler‑reactor design, and showing example code that runs concurrent fibers without altering existing PHP code.
Introduction
For many years PHP has expanded into long‑running applications where concurrent execution is crucial. Production‑ready solutions such as Wokerman, Swoole, AMPHP and ReactPHP exist, yet PHP still lacks a comprehensive mechanism for writing concurrent code without extensive rewrites.
Goals
Allow PHP developers to enable concurrency with little or no changes to existing code.
Code originally written to run outside a Fiber should work unchanged inside a Fiber.
Developers should not need to manage Fiber switching unless they deliberately intervene.
When familiar patterns like AMPHP interfaces, Go‑style coroutines, or Swoole APIs exist, the implementation should adopt the most familiar approach.
Balance flexibility and simplicity, avoiding unnecessary external library dependencies.
Provide an object‑oriented async interface that abstracts event‑loop management, handling objects such as Resume, Notifier and Callback to hide resource‑management complexity.
Proposal
Implicit Model
At the language abstraction level, two async models exist.
Explicit model : uses Promise/Future, await and async. Functions are explicitly marked as asynchronous and must return a promise‑like result.
Implicit (transparent) model : as seen in Go, Erlang or Elixir, where functions are not explicitly labeled; any function can be called asynchronously.
The true async design adopts the implicit model for several reasons:
Minimizes code and language syntax changes (the RFC introduces no new syntax).
Promotes reusability by avoiding rewrites of sequential code.
Solutions like Swoole already demonstrate the viability of an implicit model.
True async defines two core components:
Scheduler : responsible for executing Fibers (coroutines).
Reactor : implements the event loop.
In normal mode, code runs outside a Fiber unchanged. When a blocking function such as sleep(), shell_exec() or fread() is called, execution pauses as usual.
Once one or more Fibers are created via the API and the Scheduler is activated, the code begins to run concurrently.
Async\run(function(){
echo "fiber 1: start
";
sleep(1);
echo "fiber 1: end
";
});
Async\run(function(){
echo "fiber 2: start
";
sleep(1);
echo "fiber 2: end
";
});
echo "start
";
Async\launchScheduler();
echo "end
";Expected output:
start
fiber 1: start
fiber 2: start
fiber 1: end
fiber 2: end
endFrom a PHP developer’s perspective, code inside a coroutine behaves exactly like regular code; no additional effort is required to transfer control between Fibers.
The sleep function itself does not perform a Fiber switch; instead it creates a Resume object that registers a timer event. When the timer fires, the Resume updates its state and the Fiber is queued for later execution.
Developers should not assume a deterministic execution order of Fibers, as the scheduler may reorder them.
RFC References
Wiki: https://wiki.php.net/rfc/true_async GitHub:
https://github.com/EdmondDantes/php-src/tree/asyncSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
