PHP does not need a faster PHP
I learned to code in C. When you come from C you type everything by instinct and you feel uneasy when a language lets anything through. That is why I never got comfortable with untyped PHP. I spend too much time writing guardrails, checking what came in, what went out, trying to guess what will break in production because the wrong type showed up. In the last few months I maintained libraries where PHPStan does the job I wish the engine did. It works, but it is a tax.
The comment tax
If you use PHPStan or Psalm today, you already use generics. Only inside comments. The docblock pretends to be documentation and the analyzer pretends it is code.
/**
* @template T
* @param Collection<T> $items
* @return T
*/
function first(Collection $items) { /* ... */ }
More than 202k files on GitHub use this trick. It is what Brent Roose called the comment tax. The Bound-Erased Generic Types RFC by Seifeddine Gmati proposed to take it out of comments and put it in syntax. Box<int> and Box<string> would be the same class at runtime, the type would become its declared bound, no cost in prod, safety in dev. The engine would see mixed or the bound, Reflection would keep the original form for tooling. That is the erased model, like Java does.
I wanted it to pass. It made the most sense to me, and it follows what PHP Annotated has argued for, check everything during analysis and run without extra checks in production. Brent made that case in 2021 in We don’t need runtime type checks and again in his four-part series on why we cannot have generics in PHP. The PHP Foundation also mapped the alternatives in State of Generics and Collections and admitted reified is much more expensive in an interpreted language.
Erased generics as proposed are a direct continuation on this path, which is already proved viable and useful. Thanks to IDEs, static analysis in PHP has a much wider user-base than just the active users of phpstan, psalm, et al. — Nicolas Grekas, quoted in A generic tragedy
Still, I get why it did not pass. The RFC was declined in May and the Foundation had already signaled a different direction in Compile time generics yay or nay. PHP chose long ago that types are checked at runtime. When you write function add(int $a) the engine coerces or throws TypeError right there. That is how the language thinks. Adding generics that disappear would create two rules in the same house. One type that checks at runtime and another that vanishes. It sounds small, but an inconsistent language charges interest for years. Anyone maintaining something that powers a large part of the web cannot move fast. As Nuno put it, internals moves slowly for a reason.
PHP Annotated on generics in PHP and the bound-erased generics proposal. See the RFC.
TypePHP, the binary that is not PHP
That frustration is where TypePHP comes from, the former Swoole AOT renamed. It takes PHP 8.4 or 8.5, lowers it to C++17 and emits a native binary. The site shows fib(40) 135x faster than ZendVM and PI 69x. Those numbers are real and they tell half the story.
When you run bench.php and micro_bench.php from php-src itself, the gain drops to about 8x and 6.5x. Still good, but it is pure compute. A typical web app does not live on Fibonacci. The project impresses for another reason. It is written in PHP and it compiles itself, truly self-hosting, with three modes, binary, extension and shared lib. But it is not drop-in.
The incompatibility list is almost two hundred lines long. Global scope can only declare, code must live inside a function with main(), $$ does not exist, closures cannot be rebound, union still becomes mixed in the generated C++, native-typed properties cannot change type later. The README itself warns it is a defined, testable subset. Marketing says compile your PHP and be happy. Docs say bring only the part that compiles.
For CLI, games, desktop, WASM and heavy CPU work, it makes perfect sense. The repo already shows examples compiling for Android, iOS and Godot. To take a Laravel app to a binary tomorrow, it does not.
Nuno Maduro on PHP getting a compiler and why generics splits internals.
Whim, the PHP that admits it is not PHP
Whim is a different bet. It is from the same Seifeddine Gmati who wrote the RFC that did not pass, and the creator of Mago, the Rust toolchain that finally made lint and analysis in PHP fast, with 3.3k stars and over 1.6M installs. If the core would not take generics, he built the language he already analyzes. File .whim, familiar syntax, but it is not PHP.
Whim has reified generics with runtime pattern matching, the match with Box<int> versus Box<string> example, it has classes and enums, cooperative tasks and its own stdlib for HTTP and Postgres. It is interpreted, in Rust, with a live playground. It has a couple dozen stars, it is experimental. And that is where it interests me most, even though I prefer erased.
I agree with PHP Annotated, for me erased would be cleaner and faster, check in dev and run without weight in prod. But it is fine if it is not erased. Whim chose reified and I understand that choice. It does not pretend to be compiled PHP. It says it is another language that looks like PHP. It is easier to trust something that admits what it is.
Nuno also covered the recent Whim launch as basically PHP but with generics, async and pattern matching without waiting until 2030. You can feel the same tension on r/PHP, where the recurring fear is to repeat Hack, Facebook built HPHPc, then HHVM, then Hack, and the ecosystem split.
Nuno Maduro presenting Whim, the PHP-like language built in Rust.
The Mojo for PHP
Many people call both projects fragmentation, the old xkcd of creating the tool that unifies five hundred tools and ending with five hundred and one. I do not see it that way. Fragmentation assumes someone tries to replace the center. These projects are labs.
Whim for me is Mojo for Python. It will probably not succeed as the product that runs your SaaS, but it can succeed as pressure. Good ideas leak back to the center. PHP did this before. Hack was born from similar frustration and the core absorbed parts of the ideas at its own pace and with its own constraints. Even an experiment like userland-php-generics that monomorphizes a class at runtime with FFI shows people trying to measure the real cost of reified that internals says is too high.
In the AI era this matters more than it seems. I generate code with models every day and models work better the more types they have. Well typed code is more predictable for machine and human. If PHP is slow to offer real types, the barrier between languages that AI tore down works against PHP. Not because Python or Rust are always better, but because they let the generator make fewer mistakes.
I preferred erased. Internals did the right thing to say no for consistency, even if it frustrated me. Between a compiler that promises your PHP will become a native binary and a new language that admits it is not PHP, I pick the second. Not because it is faster today and not because I think reified is bad. I pick it because it does not sell a shortcut. It shows how it would look if we started again without carrying forty years of compatibility. If PHP copies a good idea from it in two years, it will have been worth it, even if no one ever does a deploy of a .whim to production.
Links to follow: Bound-Erased RFC and internals discussion, Brent’s A generic tragedy, TypePHP on GitHub and performance docs, Whim on GitHub and Mago.
>_ Comments
Loading comments...