DEV Community

Len Woodward
Len Woodward

Posted on • Originally published at youtu.be

This Week In PHP Internals | August 12, 2026

happened This Week in PHP Internals.

11 stories this week, so let's get into it. But first, Your team adopted AI. Everyone says it made them faster. Ballast measures whether that's true — how much faster you're actually going, and whether what you ship is still holding up. 6.75 times the commits. Durability down 19 points. Now you know. It runs on your machine. It reads your git history, not your source — your code never goes anywhere, and nothing here is scored by a model. It's arithmetic you could check by hand. Setting it up isn't your job either. Paste one prompt into your coding agent and it does the whole thing. Find out for free today. ballast.now.

One correction before the top story. Last week we described the list() deprecation vote as deadlocked at 21 to 21. Derick Rethans pointed out that's the wrong word — a deadlock is when something is stuck and can't proceed. The vote wasn't stuck. It was simply tied, and voting carried on to the finish. He's right, we'll say it properly this week — and thanks, Derick, for keeping us precise.

This week's top story: the verdict is in on the 35-ballot mass deprecation vote for PHP 8.6. Voting closed Monday at 13:00 UTC, and Gina P. Banyard posted the full results — 31 proposals accepted, 4 rejected. Start with the 4 that fell. Deprecating list() finished on a flat tie — 23 to 23, with 1 abstention — exactly 50 percent, nowhere near two-thirds. Reserving in, out, and inout failed at 8 to 21. The gettext _() alias survived at 10 to 22. And the dechunk filter — the item disputed all through the voting window — finished at 18 to 15 with 12 abstentions, 54.5 percent, and stays in the language.

Now last week's cliffhangers. Reserving let was balanced exactly on the two-thirds line 7 days ago — it found its margin and passed at 24 to 11, with 9 abstentions — 68.6 percent. Reserving is passed at 29 to 10, despite Rowan Tommins's warning about the Hamcrest testing library and its 500 million installs. And the define() case-insensitivity flag — the item Kamil Tekiela wanted simply deleted instead — passed without a single no vote, at 41 to 0. The vote also drew one final flag on its way out. Takuya Aramaki wrote in Friday, opening with: "Apologies for bringing this up so close to the end of the vote." His concern is the SplFileObject CSV methods item. He laid out the inconsistency plainly: "setCsvControl() is the only way to configure the delimiter, enclosure and escape character used by READ_CSV; the constructor does not accept them. If setCsvControl() is removed in PHP 9 while READ_CSV remains, READ_CSV is permanently locked to its defaults and tab-separated files can no longer be read through it." He asked that READ_CSV be deprecated alongside the methods, or that setCsvControl() stay until a replacement exists. No answer yet — and the item passed at 25 to 5, with 15 abstentions.

The final 3 ballots of the 8.6 season are settled, and they went 2 and 1. Caleb White's pipe assignment operator — |>= — was declined. The vote closed Tuesday morning at 14 yes, 12 no, and 7 abstentions — 53.8 percent, short of the two-thirds it needed. It had climbed all the way from dead even, but never got over the bar. Nick Sdot's readonly property defaults went the other way entirely. It closed Friday at 24 to 0, with 5 abstentions — it never drew a single no vote in 2 weeks. And Khaled Alam's const object property writes closed Saturday. He announced the result Sunday: accepted, 17 to 2 with 6 abstentions — 89.5 percent. With those 3 in the books alongside Duration and the deprecations, PHP 8.6's RFC season is over — the beta 1 tag brings the soft freeze this week, and beta 1 itself lands Thursday.

Ilija Tovilo posted a very late update to an RFC that passed 24 to 0 back in March. The closure optimizations RFC promised 2 things: a cache for stateless closures, and inference — the engine automatically detecting closures that never touch $this and treating them as static. That second part is out. Ilija found an edge case where a closure violates none of the RFC's inference rules and still makes an instance call — pass a callable string like "Foo::instanceCall" into an array_map inside the closure, and the rules never see it. He owned it completely, writing: "I failed to consider this case, and sadly this is not easy to detect via a new rule. For this reason, I have decided to omit static closure inference from the implementation and only merge the stateless closure cache." The practical takeaway: the cache — which carries most of the performance win — still ships in 8.6, but the engine won't infer anything for you. Mark your closures static yourself and you get the full benefit.

Ignace Nyamagana Butera's data encoding API — the base64, base16, base58, and base85 family — got a detailed security review from Sjoerd Langkemper on Monday. He's for it, noting: "the current base64_decode is very tolerant towards invalid input, causing both functional and security problems." Along the way he found errors in the RFC's own code examples, corrected them in a companion repository, and flagged a signature mismatch in the base85 functions. He's skeptical of one feature — the optional constant-time mode — arguing: "Constant-time algorithms are pretty difficult to develop and maintain", and suggesting PHP hand that job to libsodium or openssl instead. He also built a working implementation to test the API, introducing it with unusual billing: "LLMs and I have created an implementation here." And in the research footnotes: he spent real time evaluating the base85 variant from RFC 1924 before discovering: "that RFC was submitted in jest as an April fool's joke." Ignace thanked him for the remarks and is holding all implementation work until after 8.6 ships — Tim Düsterhus, who's building it, is busy with the release.

The first RFC aimed past the freeze is already here. Weilin Du proposed IntlRelativeDateTimeFormatter on Friday, targeting PHP 8.7 — a wrapper for ICU's locale-aware relative time, the "in 3 days" and "last Sunday" strings, in every language ICU speaks. Ignace asked the obvious question: 8.6 just gained a Duration class — shouldn't this accept one? Weilin argued the types don't fit, since Duration is stopwatch time and this formatter wants a unit: "We don't know how to deal with 90 minutes here. It can be 90 minutes or 1.5 hour." And weekdays, months, and quarters aren't durations at all. David Carlier pushed for enums and a namespace; Weilin is keeping class constants and the global Intl prefix for consistency with the existing intl extension, and filed modernization under future scope. One suggestion did land immediately: by Saturday the constructor had grown an optional NumberFormatter parameter, with Weilin reporting: "The implementation is way more smoother than I expected."

The generics conversation is parked until September — the implementations aren't waiting. Carlos Granados posted a pre-RFC Thursday: he took Rob Landers's experimental reified branch — built on Seifeddine Gmati's bound-erased proposal — and worked it into something complete, with a full write-up of the changes and findings. He argued the original deserved better: "I think that this was a very valid proposal that should have been explored in more detail." Rob's reply was brief, noting: "You really should have reached out instead of a working in isolation. Join us in discord, the proposal is delayed until September-ish." Which raised a practical question — what Discord? Rob posted channel links; Carlos, a Discord newcomer, still couldn't get in. Larry Garfield finally supplied the address, phpc.chat, with a review: "The PHP Community chat is unofficial, but lately it's where the big names are hanging out, including a lot of Internals regulars. Beware, the Internals channel is annoyingly noisy and has a hard time staying on topic." And I can personally vouch for that statement. Then Monday brought a third generics experiment: Alexander Lisachenko shared a userland proof-of-concept — a Composer package — where specialized classes share the compiled method bodies, so each specialization costs one small structure per method instead of a full copy of the opcodes.

Liam Hammett's native markup expressions RFC — JSX-style HTML in PHP — got the one review nobody else could write. T.J. L, who maintains the XHP extension — the long-running ancestor of this exact idea — posted his first message ever to internals. He corrected one detail in the RFC's history section, then confirmed its central argument from experience: he wrote: "While it is technically possible for extensions to add new syntax, it is unreasonable to expect tools to be aware of that syntax. I can absolutely confirm that the biggest point of friction in using XHP today is the fact that static analysis tools like psalm or phpstan can't analyze files, code using XHP cannot be formatted or linted with php-cs-fixer..." In other words, the case for putting markup in core, signed by the person who spent years doing it the other way. He also brought 3 asks: context passing through a component tree without threading attributes; a ruling on inline SVG, which leans on XML features the HTML-only RFC excludes; and a note that dropping per-tag objects means no runtime validation of tags and attributes — XHP's original selling point — which he says JSX gets away with "in large part because of the Typescript ecosystem". No response from Liam yet.

Quick hits. Juris Evertovskis ran a temperature check on isset: expressions inside the square brackets still throw warnings and deprecations even though isset silences everything else, and he put his conclusion bluntly: "To me it looks like isset is not doing its job." He'd like the brackets silenced too — no replies yet. The did-you-mean error suggestions are officially not being rushed: Jorg Sowa announced: "I will finish it after feature freeze", and Larry Garfield agreed, adding: "If it doesn't happen until 2027, that's OK." Jorg also picked up his VCS account this week — approved by Ilija Tovilo — with the session extension in his sights. And the list has a new face: Sepehr Mahmoudi introduced himself Tuesday with a pull request already open and an array_search_range idea in hand; mickmackusa pointed him at array_find_key() and suggested making the case on the list before writing more code, and Yuya Hamada thanked him for the contribution.

So that's the week: the 35-ballot deprecation vote landed 31 to 4 — list() survives on a flat tie, dechunk survives, and let squeaked through; the pipe assignment operator was declined while readonly defaults and const object writes made it in, closing out 8.6's RFC season; closure inference got walked back to just the cache; and the first 8.7 RFC is already on the table. Links to every thread are below. Thanks again to Ballast.now for supporting this week's episode. We're Artisan Build. See you next week.

Top comments (0)