DEV Community

Len Woodward
Len Woodward

Posted on • Originally published at youtu.be

This Week In PHP Internals | July 15, 2026

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

This week's episode is brought to you by Tideways. Something in production is slow — and you can't see where. Tideways takes PHP developers from slow request to root cause in minutes, with profiling, tracing, and monitoring built specifically for PHP. 5-minute install, no credit card. Start your free trial at tideways.com.

This week's top story is a brand-new keyword knocking on the door: extension. One week after Larry Garfield floated Kotlin-style extension functions at the scalar-methods RFC, Holly Schilling arrived with working prototypes of Swift-style class extensions — born, she says, out of a Discord conversation — and it became the biggest thread of the week at 26 messages. The idea: add methods to a class you don't own — extension \DateTimeImmutable gives every date an isWeekend() — and, in a later phase, put methods on scalars, so "hello" gets a length(). She published 3 draft RFCs as gists, implementation included. Michael Morris asked the obvious first question, writing: "Looking at Swift's extension syntax I fail to see anything it adds not covered by the above." — the above being inheritance and traits. Holly drew the line clean: "An extension is essentially the reverse of a trait." With a trait, the author of the class decides; with an extension, the user of the class decides.

Then came the twist. 2 days in, Holly sat down to defend her own scalar-methods implementation — and couldn't. She wrote: "Typing this email this morning gave me real hesitation. If I can’t support my own implementation, no one else should either. I immediately set out to build a better version that I could put my full weight behind." The better version came from an unexpected place: C# 14, whose new extension syntax puts the receiver right in the declaration — extension string $str — no autoboxing, no downcast headaches. She rewrote all 3 drafts and the implementation around it in a day. Not everything got absorbed so gracefully: when Alex Rock proposed an explicit extend ... with ... wiring statement, Holly apologized in advance for the bluntness, then answered: "I reject this functionality." — extensions stay file-scoped, and they never override a real method. And Pierre Joye flagged a process problem: proposals keep citing Discord conversations as their origin, while he reads only internals and GitHub — and found no reference to a php.net Discord anywhere he searched.

Gina P. Banyard's Deprecations for PHP 8.6 — the annual bundle that spent June on fire — reached its quiet milestone: the list is locked. Gina declared the RFC "frozen", with only minor amendments still allowed, and put dates on everything: "I will initiate a call to vote next week on Monday (the 20th) for the following Monday (the 27th) so that the vote is done by the 10th of August." Because items were still being added in the final week, the policy's 2-week discussion clock is what sets that gap — and the timing is deliberate, so accepted proposals can land in 8.6.0 beta 1. The week's lightest subplot: Garrett W. wants the deprecation notices themselves copy-edited — those commas are comma splices, and he'd use semicolons. Tim Düsterhus explained the house style comes from PHP error messages, and added: "The deprecation messages can still change during PR review (or even later), there is explicitly no BC guarantees for those."

Paul M. Jones's function autoloading — attempt number 5 — got smaller this week, on purpose. The declare(strict_namespace=1) directive he added last week drew a structural objection from Tim Düsterhus, who argued: "I believe the strict_namespace=1 directive is a sufficiently unrelated concern - with enormous bikeshedding potential on its own, but also sufficient usefulness on its own - such that I feel it should be its own RFC that is a prerequisite to this one. It should not be piggy-backed onto function autoloading." Paul didn't fight it. He replied: "I'm good with that. I'll prepare a separate RFC and remove that from the function-autoloading one." — and by Tuesday night it existed: strict-namespace is now its own RFC on the wiki, and mark 5 will reference it instead of carrying it. Tim also showed his cards: he built the inverse directive as an experiment a year ago, and he's firmly on team fully-qualify-everything.

Tim Düsterhus and Derick Rethans' Time\Duration class is days from the ballot box — and it picked up its first declared no. Pierre Joye spent the week pressing on fromSeconds() and its capped nanoseconds argument, and landed here: "I like that RFC, but it adds confusions and limitations from what is supposed to be a simple first step. As it stands now, despite the fact that I would love to see it, I tend towards a no." Tim's defense reached for the stopwatch — it's natural, he argued, to say Usain Bolt broke the 100 m world record with "9 seconds 58 hundreths" — exactly the fixed-point form fromSeconds() uses. Pierre countered: "It is just as common in the real world to have duration information in one unit only and decimal. F.e. 234.54ms. or 3.4 hours, etc." Neither moved — and per Tim, that's fine: "All discussions have been resolved (some of them with an “agree to disagree”), so we plan to open voting at the end of this or early next week." The 14-day cooldown runs out Friday evening, European time.

A first-time author had a very good week. Caleb White got RFC karma from Ilija Tovilo, and his first proposal — the pipe assignment operator, |>= — went through review polish at speed. The idea: $x |>= trim(...) pipes $x through and puts the result back, just like every other modify-assign operator. Tim Düsterhus liked the shape, saying: "Conceptionally I like the idea of having an “in-place modification operator” for function calls and the semantics of the operator seem to be consistent with the existing “modify-assign” operators we have, particularly also with regard to operand order. Nice idea!" Tim also caught a precedence claim that was almost right — assignment operators are not the lowest; the infamous or die() pattern depends on it — and Caleb fixed the RFC the same day, both times. The list's real energy went to naming. Ben Ramsey offered: "I like to think of |> as the volcano operator, while |>= is the erupting volcano operator."

Then last night — hours before we hit record — Liam Hammett published Native Markup Expressions: JSX-style markup as first-class PHP expressions. Write a <button> tag straight into an expression, and it compiles to new \Markup\Element(...) — escaped by default, with capitalized tags becoming components. Liam headed off the obvious reading, writing: "Despite appearances, this is not a template language grafted onto the engine - the syntax is pure compile-time sugar." First reviewer Garrett W. questioned that capitalization heuristic — PSR-4 isn't binding, and lowercase class names are legal. Liam pushed back: "Fallback resolution turns typos into silent bugs. With the capitalisation rule, fails loudly with a class-not-found error. With fallback resolution, it silently renders as a literal element and you find out in the browser, if you find out at all." This is the ambitious RFC Liam requested wiki karma for on July 10 — Ilija Tovilo granted it Monday: "RFC karma was granted. Good luck!"

Marc Henderkes wants to end PHP's double life. His pre-RFC: make ZTS — the thread-safe build — the default, deprecate the rest, and drop NTS entirely in PHP 9. He summed it up himself: "Tl;dr: nobody wants to maintain two builds and even having a necessary split is making things hard." Distros package only NTS, FrankenPHP needs ZTS, and php-src carries roughly 420 ZTS ifdefs. The performance tax is dissolving too — his numbers: "Worst case performance cost of ZTS in php 8.5 was ~5%, will be ~1.5% in php 8.6, likely ~0.5% after my last open PRs." To be clear, he is not proposing to deprecate FPM — a single-threaded ZTS run keeps everything NTS does today. 2 of the named blockers — the arm64 macOS JIT and the fuzzer SAPI — were fixed within 2 days of the thread opening; the third, NewRelic's missing ZTS support, isn't Marc's to fix. Benjamin Eberlei backed the initiative, Calvin Buckley volunteered his own PHP distribution as a test subject, and Marc has requested wiki karma to write the full RFC.

Nicolas Grekas's serializable closures spent the week absorbing a deep review from Tim Düsterhus — and then ran into a wall. Tim was candid: "While reading the RFC initially and now the updated version, I got the feeling that it was “overfitted” to solve the specific use case and deployment scenario that you consider a “best practice”, which I feel results in “weird” behavior when one leaves that happy path." Still, the 2 converged on real changes: Nicolas adopted Tim's tagged-union serialization format, and — after an off-list suggestion from Arnaud — replaced the fragile line-number check with a compile-time hash of the closure body, so a shifted use import can't silently break payloads. Then Tuesday night, Ilija Tovilo weighed in against — questioning whether attributes need caching at all, and finding the format and implementation too complex. He closed with: "Overall, I'm sadly not in favor of this RFC."

No ballot box was open this week — instead, the queue got dates. Eric Norris's minimum supported versions opens voting tomorrow, July 16 — the earliest the policy allows. Duration clears its cooldown Friday evening and opens late this week or early next. The deprecations list calls its vote Monday the 20th, with ballots open the 27th. And Khaled Alam's const-object-property-write RFC is cleared to open July 25 — no later than the 28th to make 8.6. All of it backs into the release managers' reminder from Monday. Matteo Beccati wrote: "Any RFC intended for inclusion in PHP 8.6 must have its discussion concluded and its voting closed before August 13." Soft feature freeze: August 11. Beta 1: August 13.

Quick hits, round 1. Máté Kocsis revived his query parameters RFC with a simplification: he's cutting the array API down to 2 — maybe 3 — methods, fromArray() and toArray() with withArray() on the bubble, plus an options class with security limits on parsing; League-of-URI maintainer Ignace Nyamagana Butera answered with naming notes and an enum for null handling. Nick Sdot's readonly-property defaults — zero replies when we covered it last week — got its replies: Tim Düsterhus found an unserialization wrinkle, Nick fixed it the same day, Larry Garfield is skeptical, and Tim plans to abstain. Holly Schilling — the same Holly Schilling from our top story — found that non-public asymmetric setters run roughly 4x slower than public ones, posted a fix, and then a formal RFC for it — with Ilija Tovilo reviewing the PR, she's giving the list a few days to weigh in on 8.6 versus waiting; Marc Henderkes and Calvin Buckley both questioned whether an internal change needs an RFC at all. And Osama Aldemeery's PREG_THROW_ON_ERROR settled its naming on Tim's advice: an unnamespaced PregException.

Round 2. Sjoerd Langkemper showed that newlines in CURLOPT_HTTPHEADER values inject extra headers — even over HTTP/2 — and opened a fix; upstream curl is adding its own check, and curl's own Daniel Stenberg confirmed CRLF is disallowed. Xavier Leune bumped his curl socket-callbacks PR — pitching it as the missing tool against SSRF to localhost — and is still waiting on a reply. The bundled-GD sync to libgd 2.4 drew its first pushback: Giovanni Giacobbi says the upstream code is too young and 8.6 too far along, while Pierre Joye, Jakub Zelenka, and Ilia Alshanetsky want it landed before beta 1 — Jakub's condition being that the security-review findings get addressed first — and Kamil Tekiela says wait for the next version. And the DTLS experiment in the openssl extension became a real draft PR; Jakub Zelenka confirmed the direction and is already sketching the generalization it needs.

So that's the week: a brand-new extension keyword that rewrote itself mid-thread; a frozen deprecations list with ballots set for the 27th; function autoloading shedding a prerequisite RFC; a Duration vote opening within days, carrying its first declared no; and a JSX-flavored surprise landing the night before we filmed. Nothing was voted on this week — and the ballot queue starts moving tomorrow. Links to every thread are below. Thanks again to Tideways.com for supporting this week's episode. We're Artisan Build. See you next week.

Top comments (0)