u/ProjektGopher

This Week in PHP Internals | July 1, 2026
▲ 24 r/symfony+2 crossposts

This Week in PHP Internals | July 1, 2026

Hello world, it's Canada Day 2026, and here's what happened This Week in PHP Internals.

This week's episode is supported by OurCVEs. Hundreds of CVEs ship every week, and almost none of them are about you — until one is. OurCVEs inventories your entire infrastructure and only surfaces the security risks that actually apply to your team. Free for open source at ourcves.com.

This week's top story is still Gina P. Banyard's Deprecations for PHP 8.6 — the once-a-year housekeeping RFC that gathers a stack of unrelated removals under one roof, where each one stands or falls on its own separate vote. With 8.6's first alpha getting built this very week, the clock is loud. But the fight this week wasn't about any single removal — it was about evidence: does every deprecation owe voters an impact analysis? Tim Düsterhus argued no, at least not as an unconditional rule — a deprecation has years of runway, and a survey of existing code can't measure the upside of a cleanup.

Juliette Reinders Folmer had offered to build those impact analyses, and her exchange with Tim turned personal — an accusation of gaslighting, which Tim rejected. But she was far from alone on the substance. Rowan Tommins came to her defense, and he didn't warm up first. Rowan wrote: "I hate this argument." His point: deprecating something is really a proposal to remove it later, so the impact of that removal is exactly what voters deserve to see — and to leave it out to protect your case, he said, would be dishonest. Larry Garfield backed the same call: put the impact on the table, or read the angry blog posts come December.

And this particular RFC kept growing right up against the freeze. Seifeddine Gmati proposed deprecating list(), and got the room's attention: Ayesh Karunaratne clocked "7 million hits" for list( on GitHub and called the break too big; Rowan noted you can't really retire list() while array() stays — to which Seif said, fine, then maybe deprecate array() too. Nick moved to reserve namespace as a constant name. Ilia Alshanetsky floated finally sunsetting open_basedir — Derick Rethans said "Yes, but for PHP 9," while Jakub Zelenka was firmly against it. Add a careful fight over how narrowly to kill the dechunk filter, plus Tim's pitch to retire gettype() for get_debug_type(), and that's a lot of small knives being sharpened at once.

Carrying over: Tim and Derick's Time\Duration class — the immutable stopwatch value that's meant to be the first brick of a modern date-and-time API. One line of context, then this week's moves: they're dropping the word "period" from the method names (Derick pointed out ISO itself walked away from it); they're lifting the ban on negative durations after Paweł Kraśnicki showed up with a real use case; and the whole thing may slim down for 8.6 — ship addition, subtraction and multiplication now, and let dividing one duration by another wait. Ignace Nyamagana Butera and Nick are already bikeshedding whether that division should hand you back a tuple or a tidy little value object.

The single busiest thread of the week was brand new: Rob Landers formally opened Primary Constructors — the whole constructor hoisted up onto the class line itself. His numbers are the pitch: something like 30 to 40 percent of all constructors are completely empty, and by his count 71 percent of Laravel and 61 percent of Symfony classes could use this. The catch is deliberate — a class with a primary constructor can't also declare a regular __construct, and it can't carry a body.

That no-body rule is the whole fight. Nick pushed for a body — mostly so readonly classes have a way through — and warned this could ship as yet another half-a-feature. But Rob held the line. He wrote: "If you need a body, use a constructor -- that's what they're for." Rowan and Tim are with Rob — Tim called the limitation "a feature," and put it simply: "[To] reduce typing alone is not a sufficiently strong argument in favor of a new feature." Seifeddine went further: "Personally, I really dislike this feature." His read — primary constructors don't remove repetition, they just relocate it. Larry, meanwhile, wants a Kotlin-style init block bolted on. Plenty's still unresolved — visibility, attributes, anonymous classes — so we'll be keeping an eye on this one.

Newcomer Michal Kral floated a spicy pre-RFC: methods on scalars. Write (3)->pow(2), or " hello "->trim()->upper(), with the call rewritten at compile time into a hidden helper — but only when the compiler can already prove the value is a scalar. He was upfront that he built it with an AI assistant. The reception was cool: Seifeddine's core objection is that PHP compiles one file at a time, so "the compiler already knows it's a scalar" covers almost no real code — the same line would work or fail depending on what's autoloaded. His fix, nicely put: "Solve the naming problem with naming, not by blinding the tooling." And Rob warned the whole thing leans on casts, which in PHP are dangerous(int) of the string "123password" is just 123.

Alex Pătrănescu opened a pre-RFC for runtime modules — a way to give each package its own private symbol table so two versions of the same library can finally coexist in one request. Rowan Tommins spent the week reframing it as containers — a boundary you run other people's code inside, Docker-style — and kept circling the genuinely hard part: what happens when an object crosses the wall between two containers? A second contributor, Alexander Egorov, pitched version "tags" instead; Rowan's worry is that tags leak the container's insides right back out. No code yet — but a problem the whole ecosystem feels.

The rawest thread of the week came from a user, not an internals regular. Michael Morris wrote what he openly called a "Disheartening Rant" after Edmond Dantes said his own TrueAsync RFC has, in his words, a 90 percent chance of not being accepted. Morris didn't hold back: "If you want PHP to be the next COBOL, this is how you go about it." His killer example is WebSockets — the thing PHP still can't really do on its own. Ilia Alshanetsky pushed back gently (he's actually written COBOL, and reports it isn't dead): async matters, but its reach in a request-based language is narrower than it looks.

Larry Garfield drew the line that matters — the same one that just sank generics. Larry wrote: "Don't confuse 'this is not the async we're looking for, done in a painful process' with 'we don't want async at all, ever.' The first is what happened. The second is simply untrue." His critique isn't of async — it's of how TrueAsync arrived: enormous, one author, hundreds of far-reaching decisions, feedback taken selectively. His fix is a real working group to design it together. Nobody's against the destination — they're against the map.

To the ballots — and this was a brutal fortnight for the marquee names. Seifeddine's Bound-Erased Generics closed and was declined: 7 in favour, 19 against, 10 abstaining — nowhere near the two-thirds. And Nicolas Grekas's __exists() magic method went down with it, 2 to 13. The two features that would've made the headlines both missed.

But look what did pass — the quiet, careful stuff, every one without a single No. Tim's deprecation of returning values from __construct and __destruct: accepted unanimously, 39 to nothing. Sjoerd Langkemper's cap on php://filter chains — that local-file-inclusion-to-RCE fix — accepted 30 to nothing, 2 abstaining. And Weilin Du's Locale display-keyword additions: in, 18 to nothing, 2 abstaining. And one's still live on the board — Jordi Kroon's move to lift third-party extension docs out of the manual is out in front at 25 to 1, one abstaining, with the vote closing July 3; on the side questions the room is leaning toward a php.net subpath over a separate subdomain, 14 to 8, and toward dropping the old user notes rather than migrating them, 20 to 4. The pattern's getting hard to miss: the bold swings keep getting sent back, while the tidy, well-scoped changes keep sailing home.

Quick hits. That newcomer arc — Sepehr Mahmoudi's grapheme_mask — got RFC karma and a warm discussion, then tried to call a vote for July 3 and was told, kindly, it's not ready: no discussion link, freeze period not met, window too short — the process catching a first-timer before the fall. Khaled Alam's write-to-constants RFC grew to cover class constants, so its vote slipped. Gianfrancesco Aurecchia's DTLS idea converged fast — Jakub steered it from a new class to a simple dtls:// stream, maybe no RFC needed at all. Gina volunteered to review the long-stranded snmp extension work. Seifeddine's Literal Scalar Types reached version 0.3. Jorg Sowa's case-sensitive-PHP revival was withdrawn. And PHP 8.6.0 alpha 1 got built — which is why everyone's sprinting.

So that's the week: a deprecations RFC that turned into a fight about honesty, a stopwatch class quietly going on a diet, a brand-new primary-constructors debate, a heartfelt plea for async — and the two flagship votes falling while the small ones walked right in. Links to every thread are below. We're Artisan Build. See you next week.

youtube.com
u/ProjektGopher — 5 days ago
▲ 38 r/PHP+1 crossposts

This Week In PHP Internals | June 24, 2026

Hello world, it's Wednesday, June 24, 2026, and here's what happened This Week in PHP Internals.

This week's episode is supported by Ballast — our new gauge for whether the software you ship actually lasts. Velocity tells you how fast you ship; Ballast tells you whether it stayed shipped — one durability score, read straight from your git history. No survey, no black box. Early access opens at artisan.build/ballast.

Right — Gina P. Banyard opened the annual Deprecations for PHP 8.6 RFC. It's the yearly omnibus: a year's worth of small removals, compiled by a dozen hands, each one voted on its own, and it has to be frozen by July 13. This year the sharpest exchange wasn't about any one removal — it was about evidence. Juliette Reinders Folmer pressed the point that the proposals ship without an impact analysis: "[N]one of the proposals contain a proper impact analysis," she wrote, calling it irresponsible to ask voters to decide partly blind — and she offered to build one, PHP_CodeSniffer plus PHPCompatibility, covering most of the list.

Tim Düsterhus pushed back — said the claim wasn't accurate, and reminded the list that deprecations aren't a breaking change. Juliette felt that talked past her, and answered plainly: "Tim, please don't try to gaslight me." It's worth sitting with, not laughing past: underneath the heat is a fair ask — give voters the data to decide. And by midweek it wasn't a two-person spat — Rowan Tommins backed the substance. A deprecation, he argued, is really a proposal to remove something later, so the impact of that removal is fair to weigh; he put it bluntly: "To knowingly omit information that might weaken your case would be dishonest."

So what's actually proposed for removal? A real grab-bag, each with its own argument. The _() shorthand for gettext() — and Rowan Tommins flagged that one as genuinely costly, since _() is the canonical gettext spelling and big codebases lean on it thousands of times. Reserving the keywords let, in, out, and inout. The CURLOPT_PROGRESSFUNCTION constant — where Ayesh Karunaratne argued don't deprecate it at all, just quietly remap it onto CURLOPT_XFERINFOFUNCTION and spare a few hundred maintainers the churn. Plus spl_object_hash() and metaphone().

One fresh proposal rode in on that same thread. Muhammed Arshid KV wants to deprecate SplFileObject's CSV methods — fgetcsv, fputcsv and the rest — in favour of a dedicated csv extension. But Ignace Nyamagana Butera, who maintains the league/csv library, hit the brakes: "deprecating the current API without providing at least the start of a replacement API seems premature [...] Anything else would be counterproductive at the moment." Gina's standing offer to anyone with an idea: send me the text and I'll fold it in — but I'm not writing it for you.

The single busiest thread of the week, though, was brand new. Tim Düsterhus and Derick Rethans proposed a Time\Duration class — a first-class, immutable stopwatch value, deliberately small, aimed at 8.6 so it can smooth the new Polling API's timeouts before the feature freeze. And it's the opening move of a modern date-and-time API. Fifty-some replies followed, almost all the productive kind of argument: should a negative duration carry a sign flag or just be signed seconds? What on earth do you call dividing one duration by another? Marc Bennewitz pushed hard on the representation; Paweł Kraśnicki showed up from the brick/date-time world and got a warm "welcome and thank you for contributing."

When the design drifted toward a static Duration::sum(), Larry Garfield drew a firm line: "I am 100% against a static method for adding durations. That's entirely pointless." He wants $dur1->add($dur2)like a civilized person. By Tuesday Tim had already renamed the ISO parser and added an ->absolute() method, so this one is genuinely moving.

Rob Landers opened a pre-RFC for Primary Constructors, lifted out of his old Records proposal. Picture the whole constructor promoted up onto the class line itself. The catch in Rob's version: a class with one can't also declare a __construct, so real init logic has to run through property hooks — and Nick Sdot caught the snag immediately, that hooks-only means the class can't be readonly. Larry's in, keep-it-simple, with a side of Kotlin. Rowan Tommins pushed back: "I don't think we should add extra syntax to the language just to change people's habits."

Function autoloading came back for a fifth try — Paul Jones's mark 5 of a feature internals keeps almost-shipping and never quite does. It drew the exact objection that's sunk every prior run: lean on it, forget to fully-qualify a name, and your code works by accident because something else loaded that function first — then breaks silently after a refactor. Tim Düsterhus put it flatly: "Agreed on this being a non-starter for the proposal for me." Paul's answer is a declare(strict_namespace=1) switch to kill the global fallback, plus a patient reply to Bob Weinand on why the engine simply can't retry name resolution cheaply.

To the ballots. The headline features still can't find a two-thirds. Seifeddine Gmati's Bound-Erased Generics is, as of this recording, sitting at 7 in favour, 19 against, 10 abstaining — and that's the primary; on the syntax sub-vote the C#-style in/out spelling is killing it, 24 to 2. Nicolas Grekas's __exists() magic method is underwater too, 2 to 12 with 7 abstentions. And Daniel Scherzer read the room on ReflectionAttribute::getCurrent() — stuck at 4-7-8 — and simply pulled the vote to rework it.

The focused changes, meanwhile, are clearing without a single No. Tim Düsterhus's deprecation of returning values from constructors and destructors: 37 to nothing as of recording. Sjoerd Langkemper's cap on php://filter chains — last week's local-file-inclusion-to-RCE fix — running 30 to nothing, 2 abstaining. Weilin Du's Locale display-keyword additions are in — the vote closed and the RFC's accepted, 18 to nothing. And Jordi Kroon's plan to lift third-party extension docs out of the manual is cruising at 21 to 1 — though the room is split on where they should live.

Tough week to be a revival. Jorg Sowa brought back case-sensitive PHP, took a full week of fire — Rob Landers didn't hedge: "I honestly can't think of anything good that this RFC would bring" — and on Tuesday retired it himself, writing: "I'm sorry, but I'm going to stop work on this RFC. I see very little chance it passing." James Titcumb formally walked away from the deprecate-PEAR RFC, realising it isn't really the project's call to make, and explained: "[D]eprecating PEAR is not really within the remit of the wider PHP community [...] it's like making an RFC to deprecate Packagist." Quieter movers: Literal Scalar Types reached v0.2 with strict matching by default, and the .phpc pure-code idea mutated into an alternate opening tag, <?psf, that could even carry a new_scope directive.

On the governance bench: Khaled Alam's "write to objects held in constants" RFC cleared its cooldown and is headed to a vote June 29. And Ben Ramsey reshaped the Working Groups proposal — moving the real policy text out into a pull request so the RFC itself is just charter-and-link — still trying to give the project a little structure without crowning a BDFL.

One human note to end on. A few weeks back a newcomer, Sepehr Mahmoudi, floated a get_favicon() function and got the classic "what problem does this actually solve" welcome. This week he withdrew it himself — better suited to userland, he decided — pivoted to a str_mask() helper, heard Rowan explain that real masking needs graphemes and ICU rather than raw bytes, and pivoted again to grapheme_mask() for the intl extension, working C prototype in hand. And as of this morning he's got the keys to write it up — Ilija Tovilo granted his RFC karma and signed off with a simple "Good luck!" That's the list at its best: someone turning up, listening, and getting better in the open.

Quick hits. Sjoerd Langkemper is everywhere this week — beyond the filter-chain vote, he wants base_convert to stop silently shredding entropy when you build random tokens with it, and he's adding a ValueError for invalid characters to hexdec, bindec and octdec. Osama Aldemeery floated deprecating return inside a finally block — the one silent abrupt-exit PHP still allows — backed by an impact analysis showing it hits just 12 sites across 9 packages, 3 of them actual latent bugs; it's folding into the omnibus. Pratik Bhujel's terminal extension reached v0.5.0. Gianfrancesco Aurecchia floated an Openssl\Dtls class to bring DTLS — the UDP side of TLS, the piece WebRTC needs — into the openssl extension, proof-of-concept already green. And 8.4.23 and 8.5.8 both cut release candidates.

That's the week: a deprecations RFC that became an argument about evidence and respect, a stopwatch class that swallowed the mailing list, two revivals laid to rest, and the headline votes still stalled while the small ones glide through. Links to every thread are below. We're Artisan Build. See you next week.

youtube.com
u/ProjektGopher — 11 days ago
▲ 33 r/PHP+1 crossposts

This Week In PHP Internals | June 17, 2026

[SLIDE 01 — title]


Hello world, it's Wednesday, June 17, 2026, and here's what happened This Week in PHP Internals.


[SLIDE 02 — generics goes to a vote]


We start where we left off last week: generics. Last week, this was the most traction generics had seen in years. This week, Seifeddine Gmati took his Bound-Erased Generics RFC to a vote — and he did it 
*over Larry Garfield's explicit objection*
.


Here's the thing about that vote: as of this recording, it's 
**losing**
. 7 in favor, 18 against, 5 abstaining. It needs a two-thirds majority, and it's sitting around a quarter. Rowan Tommins summed up the No camp in one line: "I want PHP to have generic types, but I want to be able to trust those types. This RFC does not deliver that." Erased generics let you write a type the engine 
**won't enforce**
 — and 18 voters decided that's a step they're not willing to take.


[SLIDE 03 — quote]


Larry had warned them. He reposted this into the vote thread for visibility: "you don't call the vote until you know you have the votes." Right now, that looks 
*prescient*
.


[SLIDE 04 — the path forward]


So what happens to generics now? Two camps are already sketching the next move. Larry's pitch: 
*don't*
 cram this into `8.6`. Make `8.6` the last of the `8.x` line, make PHP 2027 a `9.0`, and ship enforced generics there as the headline — "PHP 9, now with generics." Levi Morrison surprised himself by voting yes anyway, as a "stepping stone" you tighten later. And a non-voter writing as wheakerd made the plea of the week: don't let this collapse into "full reified generics now, or PHPDoc forever" — ship a smaller, 
**enforceable**
 subset first, interfaces and abstract classes, and grow from there. The vote runs through June 28. There's also a secondary vote on syntax — `+T`/`-T` versus `in T`/`out T` — and the C#-style in-out spelling is winning 18 to 4.


[SLIDE 05 — literal scalar types]


And honestly, Seifeddine had a 
*week*
. While his generics RFC was going down, he opened a brand-new one: Literal Scalar Types. The idea — let a parameter be typed as the literal values it actually accepts. `array_filter`'s `$mode` really only takes `0`, `1`, or `2`, but it's typed `int`, because that's all we can say today. Literal types let the signature say what it 
**means**
. David Gebler's first reaction was the obvious one — don't enums already do this? Seifeddine's answer: enums are a closed set in a new file with an import; a literal union describes existing scalar APIs and open value sets without any of that. And he found time to back a third proposal too — Jorg Sowa's revival of case-sensitive PHP. 
*Busy man.*


[SLIDE 06 — the php tag, again]


Remember `.phpc` from last week — pure-code files with no `<?php`, the proposal that collapsed so thoroughly even its biggest defender conceded? Hendrik Mennen brought it back. As a full RFC this time, with a working patch — 50 lines of C, ninety-eight hundred thirty-six tests passing, and a sub-vote on the file extension.


The reception? 
*Same as last time.*
 Matteo Beccati: "unnecessary complication for practically no real-world benefit." Kamil Tekiela took the motivation apart piece by piece. But credit to Hendrik — instead of digging in, he conceded the weak arguments and sharpened to one honest sentence: most new PHP files are pure code, the `<?php` carries zero meaning in them, and PHP is the 
**only**
 modern mainstream language that still makes it mandatory. Then he asked the room to tell him plainly — is the friction worth solving, is the mechanism wrong, or is it just not a real problem? 
*That's*
 how you run a discussion.


[SLIDE 07 — function autoloading, mark 5]


Paul Jones opened — and I'm quoting his own subject line — "Function Autoloading, mark 5." The fifth crack at letting PHP autoload functions the way it autoloads classes. Rob Landers, who wrote mark 4, replied with the dry truth: "the consensus was that the SPL autoloader needs to go, and nobody wanted more added to it... maybe the list has changed its mind. Hopefully." And the early replies bring real concerns: Anton Smirnov and Rowan Tommins both flagged the same footgun — lean on function autoloading, forget to fully-qualify a name, and your code might 
*accidentally*
 work, only because something else loaded that function first, then silently fall back to a global on the next refactor. Rowan's fix: a `declare()` at the top of the file that pins how unqualified names resolve. Function autoloading is PHP's 
*white whale*
, and attempt 5 is already drawing the hard questions.


[SLIDE 08 — the votes that failed]


Now — voting season. A lot of votes were live this week, and it was 
*brutal*
 at the top end. We covered generics. Two more are going down with it.


Nicolas Grekas put his `__exists()` method to a vote — a genuinely clever fix: a magic method that finally lets an object tell a property set to `null` apart from one that doesn't exist at all, the way `array_key_exists()` does for arrays. Beautifully argued RFC. The result so far: 0 yes, 9 no, 5 abstain. Sometimes the list just doesn't want the extra magic. And Daniel Scherzer's `ReflectionAttribute::getCurrent()` — which lets an attribute know what it's attached to — is failing 2 to 5, with Larry, Ocramius, and Benjamin Außenhofer all pushing an interface-based alternative instead.


[SLIDE 09 — the votes that passed]


But the smaller, focused stuff is 
*sailing through*
. Tim Düsterhus's RFC to deprecate returning values from constructors and destructors: 23 to nothing. Weilin Du's `Locale` display-keyword additions: 6 to nothing. Jakub Zelenka's Polling API already passed, 33 to 1, and it's merged. And a 
**security win**
 — Sjoerd Langkemper's RFC to cap `php://filter` chains at 16, which shuts down a nasty local-file-inclusion-to-remote-code-execution trick, is cruising at 26 to nothing. The pattern's hard to miss: tight, well-scoped proposals pass easily; the ambitious, magic-heavy ones are getting turned away.


[SLIDE 10 — SNMP, a follow-up]


A human follow-up, and a good one. Last week we flagged Steven Wilton, who'd shipped an SNMP module RFC and gotten total silence — "someone go help the man." This week, someone 
**did**
. Tim Düsterhus picked it up: he leveled with Steven that SNMP is niche enough that reviewers are scarce, said he couldn't do it himself — and then went and recruited one in the Foundation Slack. He left Steven a concrete checklist: rebase, undraft the ready PRs, link the RFC. Steven did all of it within 2 days. The PRs are now waiting on a reviewer. The list came through.


[SLIDE 11 — working groups & the Foundation]


On governance: Ben Ramsey's Working Groups RFC came 
**roaring back**
 this week. The idea — let the project charter small teams with real authority, so not everything needs a full-list vote. Tim Düsterhus still isn't sold; he thinks the RFC process already covers it. But the spicy moment came when Alex Rock floated whether PHP Foundation staff should be barred from voting on RFCs. Larry shut that down 
*hard*
: "the Foundation employs a majority of the people who really understand the engine — excluding them from voting would be project suicide. The Foundation has no vote. The people who do half the work, who happen to work for the Foundation, have votes. As they should."


[SLIDE 12 — modules, still churning]


The modules saga 
*refuses to die*
, and it's spinning off children. Alex Rock extended his proposal with Packages — Rust-style crates, with package-level visibility. And Michael Morris opened a whole new thread called "Containers," arguing that "namespaces in PHP are a bit of a hack" and floating containers as cleaner encapsulation. Rowan Tommins and Alex Rock are both in there. No RFC yet — this one's still at the whiteboard. But the appetite for 
**real encapsulation**
 in PHP clearly isn't going away.


[SLIDE 13 — closures & docs]


Two quieter movers. Nicolas Grekas's serializable-closures RFC — fixing the fact that `8.5`'s attribute closures silently break `serialize()`-based caches — got its first real review from Tim Düsterhus, who wants it split in two and thinks the security model is more cautious than it needs to be. And Jordi Kroon announced he'll open voting 
**Friday, June 19**
, on pulling third-party extension docs — `imagick`, `redis`, `mongodb` — out of the main PHP manual. Watch for that one to go live.


[SLIDE 14 — quick hits]


Quick hits. Xavier Leune wants to expose `libcurl`'s socket callbacks so you can do SSRF filtering natively — validate the peer IP before connect — without dropping to FFI. A newcomer pitched a `get_favicon()` function and got the classic welcome: Kamil Tekiela asking, politely, what problem it actually solves. Larry and Ilija's 5-year-old Pattern Matching RFC picked up sharp new feedback on whether a failed match should be able to fail silently. And Roman Pronskiy revised his social-media policy to add a "discretion" principle — the team can refuse a platform that's a bad fit — a quiet echo of the X.com fight from last week. And fresh overnight: Jorg Sowa's case-sensitive-PHP revival drew immediate fire. Rob Landers, flatly — "I honestly can't think of anything good that this RFC would bring" — while others flagged the 
*casing salad*
 in PHP's own built-ins, where `DateTime`, `PDO`, and `mysqli` already disagree, as the real sticking point.


[SLIDE 15 — end slate]


That's the week — and a heavy one: a generics vote going down, 3 RFCs rejected, 4 passed, and a modules debate that keeps multiplying. Links to every thread are below. We're Artisan Build. See you next week.
youtube.com
u/ProjektGopher — 19 days ago
▲ 25 r/PHP+1 crossposts

This Week In PHP Internals | June 10, 2026

[SLIDE 01 — title]


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


[SLIDE 02 — generics section]


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.


[SLIDE 03 — the footgun]


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.


[SLIDE 04 — the numbers]


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?


[SLIDE 05 — quote]


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.


[SLIDE 06 — the <?php tag on trial]


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.


[SLIDE 07 — modules]


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.


[SLIDE 08 — OPcache static cache]


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.


[SLIDE 09 — friends]


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.


[SLIDE 10 — terminal helpers]


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.


[SLIDE 11 — working groups]


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.


[SLIDE 12 — releases & votes]


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.


[SLIDE 13 — quick hits]


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.


[SLIDE 14 — end slate]


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.
youtube.com
u/ProjektGopher — 25 days ago