FrankenPHP 912,500 (https://github.com/php/frankenphp 11,369 ), now under the PHP Foundation, is a Go application server built on Caddy 7,400 with PHP embedded: one binary serves HTTP/1.1, 2 and 3 with automatic HTTPS. Version 1.12.7 (7 August 2026) is current, and its static Linux binary reports FrankenPHP v1.12.7 PHP 8.5.10 Caddy v2.11.4. Classic mode runs each request on a PHP thread. Worker mode boots your script once and feeds it requests in a loop:
<?php
[$booted, $served] = [date('H:i:s'), 0]; // runs once per worker: boot, connect, warm up
$handler = function () use (&$served, $booted): void {
$uri = $_SERVER['REQUEST_URI'];
echo 'pid ', getmypid(), " booted $booted, request ", ++$served, " $uri\n";
};
$max = (int) ($_SERVER['MAX_REQUESTS'] ?? 0);
for ($n = 0; !$max || $n < $max; $n++) {
$keepRunning = frankenphp_handle_request($handler); // superglobals are reset per request
gc_collect_cycles();
if (!$keepRunning) break;
}MAX_REQUESTS=3 ./frankenphp php-server --root public --listen 127.0.0.1:8423 \
--worker public/index.php,1 >franken.log 2>&1 & server=$!
sleep 2; for path in /a /b /c /d; do curl -s "127.0.0.1:8423$path"; done; kill $serverOutput
pid 1112 booted 09:36:39, request 1 /a pid 1112 booted 09:36:39, request 2 /b pid 1112 booted 09:36:39, request 3 /c pid 1112 booted 09:36:40, request 1 /d
$served survived between requests, so boot costs are paid once and state can leak (Worker Lifecycles). After MAX_REQUESTS a fresh copy booted in the same process: workers are threads.