Artisan Build logo
Start a project

This Week In PHP Internals - June 10, 2026

Len Woodward

The vote to remove X.com links from php.net failed to hit two-thirds, so the link stays — and when Paul Jones asked who actually controls the official PHP accou...

Hello world, it's June tenth, twenty twenty-six, and here's what happened This Week in PHP Internals.

The big one first: generics. Seifeddine Gmati's Bound-Erased Generics RFC has been the thread of the month — generics where type parameters erase at runtime, and enforcement is left to static analyzers like PHPStan and Psalm.

This week, Rob Landers crashed that conversation with working code. He spent a week building reified generics — actually checked at runtime — on top of Seifeddine's own branch.

But first, the footgun he found in erasure. Picture two catch blocks: catch HttpError<NotFound>, then catch HttpError<Forbidden>. With erasure, both become plain HttpError at runtime. The second catch is dead code. No warning. No error. It just never runs.

Now his numbers. Zero cost if you don't use generics. A single generic call — a new, a method call — costs up to about two-x a plain call. For something closer to real life, he took PSL — the PHP Standard Library, which Seifeddine himself maintains — converted it to generics, and ran its benchmark suite. Result: one-point-three to one-point-five times slower than the original, and the original does no type checking at all. That's per-operation overhead in tight library code — not your page load, which is mostly database and IO anyway. And here's the kicker: against code doing manual is_int checks on mixed, generics cost roughly the same.

His argument: if checked generics cost the same as the manual checks we all write anyway, why ship erased ones?

Frederik Bosch floated a compromise — reified in dev and CI, erased in production for speed. Rob's answer: erased generics don't prevent typos, they don't enforce correctness — "It seems unreasonable to take a step back, for speed."

And overnight, this one escalated. Larry Garfield weighed in: PHP "cannot do certain things nicely without generics," and on the reified add-on — "I think we may have finally found our way forward. And I am willing to eat some performance for that." But Ilija Tovilo pushed back on the engine side: monomorphizing classes risks the memory blow-ups Nikita Popov warned about back in 2020, the type inference behaves inconsistently, and he found crashes in the branch. Seifeddine's position: land erased generics first, evaluate reified as an opt-in later — because that 30-to-50-percent cost compounds through your whole dependency graph.

Still no vote. But this is the most generics traction PHP has had in years, and the heavyweights are now all at the table.

Story two: the <?php tag itself went on trial. Hendrik Mennen's pre-RFC proposed .phpc files — the c is for code — where the file is pure PHP from byte one, no opening <?php tag required. His argument: that tag exists because PHP started life in 1995 as an HTML templating language. In a file full of strict types and enums that never touches HTML, it's what he called "pure ceremony" — boilerplate you type because the language demands it, not because it means anything.

This week the thread finished collapsing. Derick Rethans called the idea "a lot of complexity, for dubious benefit." Casper Langemeijer pointed out every autoloader would eat an extra stat call checking two extensions. By Monday, even the thread's most active defender, Alex Rock, conceded the extension change brings only disadvantages.

So Rock pivoted. Monday he proposed two-step modules. Step one: declare(def=1) files — pure declarations, zero side effects, guaranteed at compile time. Step two: declare(module=1), adding import and export keywords, compile-time resolution, tree-shaking, a ReflectionModule class. He already has a proof-of-concept PR for step one.

Reception so far: chilly. Rowan Tommins called it "trying to wedge JavaScript's solution into PHP." And Michael Morris asked the question every proposal eventually faces: what problem are you actually solving? Rock's answer: full code isolation — hash-prefixed internals would let two versions of the same library coexist, the WordPress-plugin-conflict problem.

Then it escalated. Larry Garfield, on module-equals-file: "There is no way in hell that I'm moving dozens of classes into a single file... Let's stop trying to make module == file happen. It's not going to happen." Rock's response this morning: unveil step three — Packages, modeled on Rust crates, with package-level visibility. Rowan's counter: you could get namespace-internal classes with one keyword — "There is no step 2." And pointing at Guzzle's forty-three files: multi-file packages aren't a stretch goal, they're "the only plausible starting point." This thread is very much alive.

Story three, and the busiest thread on the entire list: Go Kudo's OPcache Static Cache. The idea — a shared-memory data cache managed by OPcache itself. Two flavors: volatile, and pinned. Think APCu, but built in.

Kudo announced voting could open as early as June fourth. It didn't. Instead, the week blew the RFC open. The API got completely rewritten — twenty-seven functions collapsed into two classes, VolatileCache and PinnedCache. Per-pool partitioning landed to answer Jakub Zelenka's security objections about shared hosting. Then Larry Garfield drew a line: "I will absolutely vote against this proposal if it ships with static methods as the API, no matter what else it contains." Nicolas Grekas is pushing to strip it down to an MVP — he's unconvinced pinned caching is even needed when FrankenPHP workers exist. Jakub said he has no review time until October, calling eight-point-six "a bit too optimistic." And by this morning Larry was musing whether the whole space just collapses to "this RFC or FrankenPHP" — Kudo's answer: yes, essentially, this is the bridge for traditional deployments.

There was a human moment in there too. Alexandru Pătrănescu gently flagged that Kudo's replies read like LLM-generated walls of text. Kudo owned it, and offered to step away from the RFC entirely. The list talked him down — they want the feature, just with shorter emails. Something to appreciate about this community.

One more, because the first time I saw this RFC name I had no idea what it meant: Friends. Daniel Scherzer wants PHP classes to be able to declare friends — a literal friend keyword, right in the class body, naming another class. A friend gets access to your protected members. Same access a child class would have — but without having to extend you.

The classic use case: a factory. Your User class has a protected constructor because users should only ever come from a trusted source. Declare the factory a friend, and it can call that constructor directly. No reflection hacks, no @internal docblock and crossed fingers.

The week's development: friends originally got private access too, but after pushback from Rob Landers and Larry Garfield, it's been scaled back to protected-only. That counts as a major change, so the RFC restarts its fourteen-day cooldown. Friendship is not mutual, not transitive, and not inherited — which is also just good life advice.

Closer to home for anyone who lives in the terminal: Pratik Bhujel's native terminal helpers. Derick Rethans reviewed the API earlier this month — a Terminal class in a Terminal namespace, plus enums — and by Saturday, Bhujel had shipped v0.4.1 implementing the entire reviewed design. The open question he's asking the list: keep hardening this as a PECL extension, or aim for core? If you've ever fought raw mode and ANSI escapes in PHP by hand, this is one to root for.

On the process side: Ben Ramsey's Working Groups RFC — formalizing small teams with delegated authority over specific areas, so not everything needs a full-list debate. Larry Garfield is strongly in favor. Tim Düsterhus is skeptical: policy changes should just be pull requests to the policies repo, and the RFC process already covers the few teams PHP actually needs. Governance isn't glamorous, but this one shapes how every future RFC gets decided.

Housekeeping: PHP 8.4.22 and 8.5.7 dropped Thursday. Bugfix releases, nothing scary — upgrade when convenient. Voting opened on Weilin Du's Locale RFC — getDisplayKeyword and getDisplayKeywordValue, filling a small ICU gap in the internationalization extension, targeting 8.6. Six to nothing in favor; vote runs through June twenty-third.

Two more from Nicolas Grekas, just this morning: the underscore-underscore-exists RFC opens for voting Sunday. And a brand-new RFC — serializable closures from constant expressions. The problem it fixes: those nice closures PHP 8.5 lets you put in attributes and property defaults can't be serialized, which silently breaks every serialize-based metadata cache. Fresh thread, watch it develop.

Quick hits. The vote to remove X.com links from php.net failed to hit two-thirds, so the link stays — and when Paul Jones asked who actually controls the official PHP account on X... nobody answered. Mark that one unresolved. A thread questioning whether disable_functions is a real security boundary resolved itself in twenty-five minutes — the warning already exists in the English docs, it's just missing from translations. Daniel Scherzer announced he'd open voting on ReflectionAttribute getCurrent — and immediately caught fresh objections, with Benjamin Außenhofer preferring an interface over a magic static method. No vote yet. And Steven Wilton asked a simple question: his SNMP module RFC passed, so... what happens now? The list's answer, a week on: silence. Someone go help the man.

That's the week. Links to every thread are below — externals dot io if you want the raw feed. We're Artisan Build. See you next week.

Building something with Laravel?

We embed senior teams to design, ship, and steady your product.

Work with us
Share this article

Let’s talk

We want to hear about your company. What you're building, what's working, and what you wish you could improve.

  • Be confident in your security posture
  • Keep control of your token cost
  • Improve quality across your entire stack

Ready to start the conversation?

You can book a quick intro call or send us an email. No pressure, no forms — just a friendly hello.