PHP compatibility and project lifecycle
Supported PHP versions, current ReactPHP version, license and support status are unknown from the supplied excerpts. Only fibers in PHP 8.1+ for await are mentioned. The examples target PHP 8.4.
Official sources checked 2026-10-22. Browser lessons on this site run PHP 8.5.
What ReactPHP is
According to the official site, ReactPHP is a low-level library for event-driven programming in PHP. At its core is an event loop. On top of that loop it provides low-level utilities: a streams abstraction, an async DNS resolver, a network client and server, an HTTP client and server, and interaction with processes. Third-party libraries can build async network clients and servers on these components.
Classification: a library, not an interpreter
ReactPHP is an async library and event loop that runs on the ordinary PHP interpreter. It is not a standalone PHP runtime, a fork of PHP, or an alternative interpreter. It is also not a framework or a CMS product. PHP core supplies the language and engine, and ReactPHP is a set of Composer-installed components that your own script uses.
A few distinctions help avoid confusion:
- Swoole and Open Swoole are separate projects. They are not ReactPHP, and the supplied ReactPHP sources do not discuss them.
- Framework adapters that run applications on top of an event loop, if they exist, are adapters. The supplied sources do not cover any, so how a specific framework or CMS such as Drupal would run on ReactPHP is unknown here. Check that project's own official documentation.
- HHVM and other historical interpreters are unrelated to this guide.
Architecture and execution model
The HTTP page describes an event-driven, streaming HTTP client and server built on ReactPHP's Socket and EventLoop components. The client can send any number of async HTTP and HTTPS requests concurrently. The server can build plaintext HTTP and secure HTTPS servers that accept requests from clients such as browsers. Because the work is async and streaming, one process can handle multiple concurrent requests without blocking.
The client is promise-based. Methods on React\Http\Browser such as get() and post() return a promise that fulfills with a PSR-7 response or rejects with an exception. A pending promise can be cancelled, which rejects it and cleans up the underlying resources. Responses are buffered in memory by default, and the docs point to requestStreaming() for large or unknown-size bodies.
The docs also describe a blocking-style option through reactphp/async. It lets you await a promise, and it relies on fibers in PHP 8.1 and later, with a compatibility API for other supported versions. The exact supported PHP range is not stated in the supplied excerpt, so it is unknown here.
Classic request lifetime versus persistent workers
In the classic PHP model, a web server hands each request to a fresh PHP execution. Variables, objects and static properties disappear when the request ends. A ReactPHP server is different. A single PHP process starts, creates the event loop, listens on a socket, and then serves many requests from the same process memory. That is a persistent worker.
The handler function you pass to HttpServer is invoked for each request, but anything it captures or stores elsewhere survives between requests.
State leakage and cleanup
Persistence is the main practical risk. Common leakage sources in any long-running PHP process include:
- Static properties, globals and singletons that hold request data such as the current user, locale or tenant.
- Service containers or caches that keep per-request objects alive.
- Arrays that grow with every request and never shrink, which leaks memory.
- Pending timers, promises and open streams that are never cancelled or closed.
Cleanup guidance, as general practice rather than something the supplied sources prescribe:
- Keep request-specific data in local variables inside the handler, and never in long-lived objects.
- Treat shared state as deliberate and bounded, with explicit reset or expiry.
- Cancel promises you no longer need, since the docs say cancelling releases underlying resources.
- Prefer streaming for large bodies to avoid holding them in memory.
- Limit concurrency. The docs warn that sending too many requests can exhaust your resources, and they mention a queue library and the
LimitConcurrentRequestsMiddlewareclass. - Have a process supervisor restart workers if you adopt that policy. Whether to recycle workers is your decision, and the sources are silent on it.
The second example below makes this concrete with a counter that survives across requests.
Practical use cases
The sources point to several uses. You can fetch many remote HTTP endpoints concurrently, build a small HTTP or HTTPS server, stream large responses chunk by chunk, and combine HTTP work with other async I/O in one process. The HTTP docs also mention interaction with processes and several proxy types (HTTP, SOCKS, SSH) and Unix domain sockets for the client. Its server docs list middleware, including request body buffering and parsing. Note that ReactPHP is low-level, so you assemble routing, validation and persistence yourself or through third-party libraries.
Installation approach
Installation uses Composer. The supplied excerpt lists an Install section in its table of contents but does not include its text. The example therefore uses composer require react/http. Verify the package name against the official install section during review. Quickstart code loads vendor/autoload.php and uses React\Http\HttpServer, React\Socket\SocketServer and React\Http\Message\Response. These are the only APIs the examples use.
The examples are CLI scripts. They need PHP, Composer and the ability to download packages, so they are not browser exercises. The examples do not use Docker Compose, because the sources provide no container image or Compose guidance and none is invented here.
Strengths
- Concurrent, non-blocking I/O inside ordinary PHP.
- A composable set of components (loop, sockets, streams, DNS, HTTP).
- Streaming support for large messages.
- Cancellable promises and configurable timeouts.
- Middleware hooks on the server.
Limitations
- It is not a framework, CMS or interpreter, and it provides no application structure of its own.
- Persistent-process state leakage is your responsibility.
- A long-running CLI process needs a supervisor, and the supplied sources do not describe one.
- Blocking code, such as slow synchronous calls inside a handler, can stall the whole loop. This follows from the single-loop design.
- Current version, license, PHP 8.4 or 8.5 compatibility and support status are not stated in the supplied excerpts, so they are unknown.
Deployment notes
The sources do not cover production deployment, reverse proxies, TLS configuration details or process management, so treat those as unknown and consult the official documentation. For local learning, bind to 127.0.0.1 as the quickstart does. ReactPHP's server speaks HTTP directly, and the examples involve no FastCGI. Never expose a development listener on a public interface.
Learning track note
This track stays on PHP 8.4, with PHP 8.5 planned. The examples are written for PHP 8.4, but whether ReactPHP supports it must be confirmed from official sources during review.
Links
Use the official ReactPHP site and its HTTP component page, both listed below.
Practical examples
These examples have not been run in a live environment yet. Commands and versions follow the official documentation linked on this page; check them before relying on them, and report a problem if one does not work.
Minimal ReactPHP HTTP server on 127.0.0.1
A Composer-based CLI script that starts a ReactPHP HTTP server on 127.0.0.1:8080 and answers every request with Hello World!, adapted from the official quickstart. Requires Composer and network access to download packages.
reactphp-hello/server.php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
$http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
return React\Http\Message\Response::plaintext(
"Hello World!\n"
);
});
$socket = new React\Socket\SocketServer('127.0.0.1:8080');
$http->listen($socket);
echo 'Listening on http://127.0.0.1:8080' . PHP_EOL;
Install and run
cd reactphp-hello
composer require react/http
php server.php
curl http://127.0.0.1:8080/Expected behavior
After php server.php starts, the process stays in the foreground and prints the listening address. In a second terminal, curl should receive the plaintext body Hello World! for any request path. Stop the server with Ctrl+C.
Not a browser exercise. Needs PHP, Composer and network access. The package name react/http should be checked against the official Install section, which is not in the supplied excerpt. PHP 8.4 compatibility is unverified. The server is plaintext HTTP for local learning only.
Persistent worker state: a counter that survives requests
Shows that a ReactPHP server is one long-lived process. A counter captured by the handler closure keeps increasing across requests, while a local variable resets each time. Use it to reason about state leakage.
reactphp-counter/counter.php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
// Shared state: lives as long as the PHP process, across all requests.
$totalRequests = 0;
$http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) use (&$totalRequests) {
// Per-request state: recreated on every call, so it cannot leak.
$thisRequest = 1;
$totalRequests++;
return React\Http\Message\Response::plaintext(
'process total: ' . $totalRequests . ', this request: ' . $thisRequest . "\n"
);
});
$socket = new React\Socket\SocketServer('127.0.0.1:8081');
$http->listen($socket);
echo 'Listening on http://127.0.0.1:8081' . PHP_EOL;
Install and run
cd reactphp-counter
composer require react/http
php counter.php
curl http://127.0.0.1:8081/
curl http://127.0.0.1:8081/Expected behavior
The first curl should print process total: 1, this request: 1. The second should print process total: 2, this request: 1. This shows that process-level state persists between requests while local variables do not.
Not a browser exercise. Requires Composer and network access. The counter is deliberately unbounded shared state for teaching, and real code should avoid storing request-specific data this way. Restarting the process resets the counter. PHP 8.4 compatibility is unverified.