TrueAsync Server
(PHP 8.6+, true_async_server 0.6+)
TrueAsync Server ist eine native PHP-Extension, die einen leistungsstarken HTTP-Server direkt innerhalb des PHP-Prozesses ausführt. Ohne separaten Daemon, ohne Reverse-Proxy, ohne FastCGI-Brücke.
Standardmäßig werden HTTP/1.1 und HTTP/2 auf demselben TCP-Port unterstützt. Die Protokollwahl erfolgt über ALPN-Negotiation (bei TLS) oder HTTP Upgrade. HTTP/3 läuft über denselben UDP-Port (QUIC) und wird Clients per Alt-Svc-Header angekündigt.
WebSocket, SSE und gRPC sind bereits für dasselbe Single-Listener-Modell mit Protokollerkennung entworfen, befinden sich aber noch in Arbeit (siehe Roadmap).
use TrueAsync\HttpServer;
use TrueAsync\HttpServerConfig;
$server = new HttpServer(
(new HttpServerConfig())
->addListener('0.0.0.0', 8080)
->setWorkers(4)
);
$server->addHttpHandler(function ($request, $response) {
$response->setStatusCode(200)->setBody('Hello, World!');
});
$server->start();Motivation
Ziel des Servers ist es, das Potenzial konkurrenter PHP-Anwendungen voll auszuschöpfen.
TrueAsync hat der Sprache echte Coroutinen, nicht-blockierendes I/O und Connection-Pools gegeben. Damit dieses Potenzial unter Produktionslast wirksam wird, braucht es einen Server, der von Grund auf für dieses Modell konzipiert ist: einen langlebigen Prozess mit Event-Loop, in dem jede Anfrage ihre eigene Coroutine bekommt und der Scheduler bei jedem I/O-Wait zwischen ihnen wechselt.
TrueAsync Server ist genau dieser Server. Keine Zwischenschicht zwischen Coroutinen und Netzwerk: Listener, Protokoll-Parser, Request-Dispatcher und Handler leben in einem Prozess und in einem Event-Loop. Datenbankverbindungen werden über Async\Pool wiederverwendet, Opcache bleibt zwischen Anfragen warm, der Cold-Start fällt einmal bei start() an.
Funktionen
| Status | Funktion | Details |
|---|---|---|
| ✅ | HTTP/1.1 | Vollständige RFC-9112-Konformität, Keep-Alive, Pipelining (über llhttp, derselbe Parser wie in Node.js) |
| ✅ | HTTP/2 | Multiplexing, Server Push (libnghttp2 ≥ 1.57, Floor für CVE-2023-44487) |
| ✅ | HTTP/3 / QUIC | UDP-Transport über libngtcp2 + libnghttp3, OpenSSL 3.5 QUIC TLS API |
| ✅ | TLS 1.2 / 1.3 | OpenSSL 3.x, ALPN-Negotiation, schwache Cipher deaktiviert |
| ✅ | Komprimierung | gzip (zlib-ng / zlib), Brotli, zstd: für Responses und Decoding eingehender Bodies in allen Protokollen |
| ✅ | Multipart / File Uploads | Streaming-Zero-Copy-Parser |
| ✅ | Backpressure | CoDel (RFC 8289), adaptive Accept-Pausierung unter Last |
| ✅ | Streaming Request Body | Optional über HttpRequest::readBody(); Uploads ohne Body im RAM zu halten |
| ✅ | sendFile | Effiziente Auslieferung von Dateien direkt aus dem Handler |
| ✅ | Built-in Worker Pool | setWorkers(N): N Threads über Async\ThreadPool + SO_REUSEPORT |
| ✅ | Per-Request Scope | Jeder Handler in eigenem Scope; Async\request_context() liefert gemeinsamen Kontext für den gesamten Coroutine-Baum der Anfrage |
| ✅ | Native Coroutinen | Tiefe Integration mit TrueAsync: jedes blockierende I/O im Handler suspendiert die Coroutine, nicht den Thread |
| ✅ | Zero-Copy | Minimale Allokationen auf dem Hot Path |
| 📋 | WebSocket | RFC 6455, Upgrade von HTTP/1.1 und HTTP/2 |
| 📋 | SSE | Server-Sent Events |
| 📋 | gRPC | über HTTP/2, unary und streaming |
Architektur: Single-Threaded Event Loop
Dasselbe Modell wie bei NGINX, Envoy, Node.js und Rust Tokio/hyper.
Ein Thread besitzt sowohl die Verbindung als auch die Anfrage von accept bis send. Keine Übergabe zwischen Accept-Thread und Worker-Thread, keine Locks, keine Kontextwechsel zwischen ihnen. Ein Event-Loop akzeptiert die Verbindung, liest Bytes aus dem Socket, parst HTTP, dispatcht die Anfrage zum Handler und schreibt die Antwort, ohne den Thread zu verlassen.
┌─────────────────────────────────────────┐
│ Event Loop Thread │
│ │
accept ─► parse ─► dispatch ─► respond │
│ ▲ │ │
│ └──── coroutine yield ◄──┘ │
└─────────────────────────────────────────┘Nicht-blockierendes I/O übernimmt der libuv-Reactor (über TrueAsync). Wenn eine Coroutine auf eine Datei, eine DB oder den nächsten WebSocket-Frame warten muss, übergibt sie die Kontrolle an den Event-Loop, der sofort das nächste fertige Event aufnimmt. Der Thread bleibt nie in read()/recv() stehen.
Für Skalierung über CPU-Kerne hinweg wird Multi-Worker über setWorkers(N) aktiviert: Der integrierte Async\ThreadPool startet N OS-Threads, jeder mit eigenem unabhängigem Event-Loop, und SO_REUSEPORT (Linux/BSD) sorgt dafür, dass der Kernel eingehende Verbindungen verteilt. Kein Shared State, keine globalen Locks.
Einstieg
- Schnellstart: Installation und Minimalbeispiel in 5 Minuten
- Konfiguration: Listener, Workers, TLS, Timeouts, Body-Streaming, Bootloader
- Komprimierung: gzip / Brotli / zstd, Aushandlung, BREACH
- Statische Dateien und sendFile:
StaticHandler, precompressed Sidecars, Range - Streaming: Request-Body-Stream und Response-Stream
- Multi-Worker:
setWorkers(N), Bootloader, Per-Request Scope - Beispiele: JSON-API, Statik, Fan-Out, Multipart Upload
- Architektur: Interna
API-Referenz
TrueAsync\HttpServerTrueAsync\HttpServerConfigTrueAsync\HttpRequestTrueAsync\HttpResponseTrueAsync\StaticHandlerTrueAsync\SendFileOptionsTrueAsync\UploadedFileTrueAsync\LogSeverity- Ausnahmen
Alternativen
FrankenPHP ist ein eigenständiger einbettbarer Server auf Basis von Caddy/Go, in dem PHP als Worker fungiert. Praktisch, wenn man Caddy-Features (automatisches Let's Encrypt, Konfiguration über Caddyfile) oder die Integration in eine bestehende Caddy-Infrastruktur benötigt. TrueAsync Server ist die native Alternative ohne Go-Runtime: Der Server lebt direkt im PHP-Prozess.