Stack Patterns ■ Episode 06
Seventy-Two Per Cent
72% of the web runs on PHP. This is not an accident. Upload a file, it executes. No build step. No compilation. No deployment pipeline. WordPress powers 43% of all websites. Laravel made it elegant. PHP 8.4 ships enums, readonly properties, and a JIT compiler. For request-response work, PHP is rather good at its job.
It also carries thirty years of luggage. Type coercion that surprises even its advocates. A security history that required rewriting entire APIs from scratch. Legacy it cannot retire without breaking the web it runs on.
But the more interesting observation is architectural. The web has moved. Persistent connections. Live data pushes. Minimal memory footprints. PHP was not built for this. Not a criticism. A design decision, made in 1995, when "the server" meant "generate HTML and close the connection."
The Architecture
PHP's share-nothing architecture is one of the cleanest ideas in web development: every request starts from scratch. No shared state. No leaked context. No previous request contaminating the next one. Beautiful for isolation. Structural impediment for anything that requires keeping a connection open.
Async PHP exists. Swoole, ReactPHP, Revolt. They are real engineering efforts and they work. They also fight the language's fundamental design: PHP never returns freed memory to the operating system. Long-running processes leak. The workaround is to restart worker processes periodically, which is rather like fixing a dripping tap by replacing the sink every hour.
Five Languages, One Task
The task is simple in specification and revealing in execution: hold persistent connections and push live data. WebSocket, Server-Sent Events, long-polling. The kind of workload that keeps connections open for minutes or hours rather than milliseconds. Five languages. Same task. Rather different outcomes.
Java brings Spring Boot and the JVM. Approximately 200 MB before the first byte of application code runs. Deployed before the deployment finishes. PHP needs Swoole or ReactPHP to hold connections at all, and each worker process carries 40 to 128 MB of memory overhead. On a 16 GB server, that is 96 concurrent workers. Python brings elegance and the GIL, which serialises all CPU-bound work onto a single thread. Elegant until load disagrees.
Three eliminated by overhead. Two remain.
The Fair Fight
Go versus Rust. Both compile to a single binary. Both handle ten thousand concurrent connections without visible strain. Both have communities that would rather debate the other's shortcomings than examine their own. The comparison, then, must be structural.
Go assumed garbage collection was free. It is not. Every few milliseconds, the garbage collector pauses to inspect memory, decide what is still alive, and reclaim what is not. For a web server handling short-lived HTTP requests, these pauses are invisible. For a server holding ten thousand persistent connections, every connected client feels every stutter.
Rust has no garbage collector. Memory is freed deterministically when ownership ends. No pauses. No tuning. No prayer-based capacity planning.
Discord ran both in production. Go: latency spikes of 10 to 40 milliseconds every two minutes from garbage collection. Rust: consistent microsecond latency. No spikes. "Rust beat Go on every single performance metric." They did not switch back.
The Larger Question
256 MB per instance versus 2 MB. This is not a rounding error. It is up to a 128-fold difference in resource consumption for identical functionality.
Every server that need not exist is raw material never mined, water never consumed, energy never spent. The industry's answer has reliably been to throw hardware at the problem. Marvellously affordable, until the invoice arrives at both ends: hardware that costs money, and data centres consuming water where none remains.
Efficient software is not an optimisation. It is resource conservation. The difference between one Java instance and 128 Rust instances in the same memory allocation is not academic. It is the difference between scaling by spending and scaling by engineering.
When PHP Is Right
Request-response. Content management. E-commerce. CRUD applications. PHP does these superbly. The 72% chose before the alternatives existed, and for those workloads, they chose correctly. WordPress, Laravel, Symfony: these are not accidents. They are the result of a language that is extremely good at a specific class of problem.
But when the server holds connections open and pushes live data, it is a different workload. Different workload, different tool. One does not criticise a screwdriver for being a poor hammer. One reaches for the hammer.
The Point
72% of the web chose PHP. They were not wrong. They were solving request-response, and PHP does that with the casual competence of a tool that has had thirty years of practice.
But when the question changes from "generate a page" to "hold a connection," the answer changes with it. 256 MB per instance versus 2 MB is not a debate. It is arithmetic. Three languages eliminated by overhead. Two remain. One has a garbage collector that pauses every two minutes. The other does not.
Efficient software is not a luxury. It is responsibility.