Synchronous PHP

Why PHP Is Synchronous by Default

In PHP's shared-nothing model (How a Request Becomes a Page), a PHP-FPM worker runs one request top to bottom and then forgets everything. Every call blocks until its answer is in, and concurrency comes from running many workers (FPM Pools). That is simple and robust, but a request with several independent waits pays for each in turn. The demos call a local endpoint on port 8323 that sleeps 0.5 s and echoes its id as JSON, served by FrankenPHP 912,500 's threaded server (FrankenPHP and Worker Mode): php -S with PHP_CLI_SERVER_WORKERS=8 took 1.51 s for six concurrent requests, queuing them per worker.

Three blocking calls in a rowPHP
<?php
$t0 = hrtime(true);
foreach ([1, 2, 3] as $id) {
  $json = file_get_contents("http://127.0.0.1:8323/?id=$id");   // waits 0.5 s each time
  printf("%.2f s  %s\n", (hrtime(true) - $t0) / 1e9, $json);
}
Output
0.50 s  {"id":1}
1.01 s  {"id":2}
1.51 s  {"id":3}
Blocking calls wait in turn; an event loop overlaps the waits
Blocking calls wait in turn; an event loop overlaps the waits

An event loop keeps one thread but never idles on one socket: it asks the kernel (select, epoll) which connection has data and runs the code waiting for it.