u/ProjektGopher

This Week In PHP Internals | August 12, 2026
▲ 35 r/symfony+2 crossposts

This Week In PHP Internals | August 12, 2026

While the Internals list is not technically directly Symfony related, it does affect every single one of us.

Hello world, it's Wednesday, August 12, 2026, and here's what 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.

youtube.com
u/ProjektGopher — 7 days ago
▲ 29 r/symfony+2 crossposts

This Week In PHP Internals | Aug 05, 2026

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

13 stories this week, so let's get into it. But first, This week's episode is brought to you by Tideways. When a request is slow in production, Tideways takes you from symptom to root cause in minutes, with profiling, tracing, and monitoring built specifically for PHP. It installs in 5 minutes, there's no credit card required, and it's hosted in Germany. Start your free trial at tideways.com.

This week's top story: the mass deprecation vote for PHP 8.6 is in its final week. All 35 ballots close Monday, August 10, and Gina P. Banyard posted the 1-week reminder so nobody gets caught out. Most of the 35 are passing comfortably. The interesting ones are the holdouts. list() is now deadlocked at 21 to 21 — a flat tie, nowhere near the 2/3 it needs. Reserving let stands at 22 to 11, which is exactly two-thirds — a single vote in either column decides it. The dechunk filter sits at 17 to 15 — still well short. The gettext _() alias is failing at 9 to 20, and reserving in, out, and inout is failing at 7 to 20, with 12 abstentions. Everything else you'd recognize from the list — the object-parameter cleanups, the is_double() family, spl_classes() — is cruising toward the finish.

The thread itself turned into a corrections desk this week. Calvin Buckley relayed a note from Nora, who isn't on the list, pointing out: "The text for the metaphone deprecation isn't fully right. It lists "linguistics" as a replacement package, but that one actually uses php-src's metaphone internally too." Weilin Du, who proposed that item, conceded the docs point while standing by the idea, writing: "My point in deprecating it is to stop using ancient metaphone algo as a whole." Voters seem unbothered — metaphone stands at 19 to 6, with 15 abstentions. Rowan Tommins raised a bigger flag on reserving is: it would collide with Hamcrest, the test assertion framework, whose PHP port has 500 million Packagist installs and an is() function all over its README. He urged: "I think we should think very carefully whether we can avoid disrupting that much code." So far the voters disagree — is stands at 26 to 9. Meanwhile Sjoerd Langkemper, who proposed the contested dechunk item, stepped back from the argument with unusual candor, writing: "the discussion phase wasn't properly completed yet, and I did a poor job in merging all opinions into a RFC proposal." He'd rather let the voting play out — and he closed by asking Jakub Zelenka, who led last week's objections, whether anyone could help lighten his workload. And Kamil Tekiela's question from last week — why deprecate define()'s dead flag instead of just deleting the parameter — got its answer: Tim Düsterhus pointed out that deleting it isn't silent, since extra arguments throw an ArgumentCountError, and concluded: "Making it explicit (and deciding) that the parameter will go in PHP 9 is a good thing."

Function autoloading — Paul M. Jones's 5th-generation attempt — went to a vote Thursday afternoon. It lasted about a day. Matteo Beccati opened the replies with praise and a caveat, calling it "the best autoloading proposal up to date" but adding: "Perhaps I'm biased as RM, but last minute RFCs are making me nervous, I hope you understand." Then Tim Düsterhus spotted the procedural problem, writing: "In fact the start of the vote is in violation of our policy, since there was no "intent to vote" message in the last 7 days." Paul's intent notice was 2 weeks old, and a July 15 revision had reset the clock besides. Paul took it entirely in stride, replying: "Ah so -- my apologies. I'll pull the vote and wait for ... looks like ~6 weeks?" For the record, the widget stood at 2 yes to 11 no when he pulled it — so the pause may be a mercy. Tim ran the math: cancellation carries a 2-week cooldown, so a mid-August reopen is technically possible, but he judged it "likely not useful to reopen the vote without making further changes" — and offered one: resolve namespaced functions before falling back to globals. Rowan Tommins countered that the fallback path makes that slow, and pointed instead at Michael's namespace-autoloader idea — loading a whole namespace's functions at once — calling it "a much cleaner way forward". Paul is unbothered, saying he'll "come back to it after 8.6 is fully out the door." That's the 2nd vote in 2 weeks pulled by its own author over the intent-to-vote rule.

Seifeddine Gmati's literal scalar types will not be reopening. His retraction last week came with a plan to re-vote; this week he canceled that too, after asking the release manager exactly where the freeze line sits. The answer: the effective cutoff isn't the beta 1 announcement on August 13, it's the creation of the beta 1 tag on August 11 — and a vote opened now would close after the tag exists. So the RFC is retargeted to the next PHP version, text final, intent withdrawn. Matteo Beccati apologized for the ambiguity, admitting his emails "were pointing the 13th as deadline for RFCs", and went further: "having RFCs end voting so close to the feature freeze is a terrible idea as it gives very little wiggle room in case something unexpected comes out ...". Seifeddine took it well, noting his own retarget email had already started a 14-day cooldown anyway — in his words, "8.6 was out of reach the moment that email hit the list." Pierre Joye pushed back on the caution, arguing: "beta phases exist exactly for this reason. wider base of testers." He also vented about the calendar: between the new policies and the Christmas quiet period, "the time left in a year is low, very low, now." And with the clock pressure gone, Tim Düsterhus gave the RFC one more read and found just one loose end — the matching-semantics vote has no explicit tie-breaker — and otherwise signed off: "No further comments to the contents of the actual proposal."

Two carryover votes are now in the books, and both passed emphatically. The Time\Duration class closed Friday. The primary finished at 35 to 1, with 2 abstentions — 97 percent. The naming question went to full method names — multiplyBy, divideBy, negate, absolute — at 30 to 2. So PHP 8.6 officially gets a Duration class. The minimum-supported-versions RFC closed Thursday. Requiring autoconf 2.71 passed at 27 to 2, with 5 abstentions, and requiring COM_RESET_CONNECTION passed clean at 26 to nothing. That second one has a coda. Alexander Kurilo — who'd argued during the vote that the connection-reset change carries an undisclosed BC break — requested RFC karma on Saturday to propose making the new behavior optional. Ilija Tovilo granted it Tuesday, with a reality check, noting: "the vote result was quite clear, and the time for another RFC discussion + vote has run out." He left any next step to the release managers.

Three ballots are still open, and none of them drew a single email this week — the voting is doing the talking. Caleb White's pipe assignment operator closes next Tuesday. As of recording it stands at 12 yes, 10 no, 6 abstaining — 54.5 percent, needing two-thirds. It has climbed from dead even, but the gap is real. Nick Sdot's readonly property defaults closes Friday morning. It still hasn't drawn a single no — 22 to nothing, with 5 abstentions. And Khaled Alam's const object property writes closes Saturday. That one sits at 14 to 2, comfortably above the line.

A new discussion opened Saturday: Sjoerd Langkemper wants to stop curl_setopt from leaking secrets into stack traces. The problem is that one function sets everything, and he laid it out cleanly: "The value for CURLOPT_PASSWORD is likely sensitive, the value for CURLOPT_RETURNTRANSFER is not, and CURLOPT_URL may be sensitive sometimes." He brought 3 options, 2 of them with working pull requests: blanket-mark the value as sensitive and lose debug info; teach curl_setopt which options are secret, at an engine-level performance cost; or make callers wrap secrets in a SensitiveParameterValue. Iliya Miroslavov Iliev questioned the premise, arguing stack traces shouldn't be reachable in production at all — and asked how you'd debug a wrong password you can no longer see. Matthew Weier O'Phinney leaned opt-in, warning that automatic detection "will be difficult and a game of whack-a-mole", since options carry arbitrary headers and content — and floated letting the engine accept sensitive-value wrappers on any function call, so callers could opt in regardless of the signature.

Jorg Sowa wants PHP's undefined-function errors to answer back. His pull request adds "did you mean" suggestions — call defined() when you meant define(), and the error names the function you were probably reaching for, the way Python and Ruby already do. His question to the list was procedural: does this need an RFC, or is PR consensus enough? Sjoerd Langkemper answered with the policy exempting error messages from the BC rules, noting: "rephrasing error messages is not subject to the backwards compatibility break policy" — and he's in favor. Matteo Beccati liked it too, suggested Python's exact shape for the message, and nudged the list for feedback given the freeze is days away. If the sentiment holds, Jorg wants to extend it to methods, classes, and constants next. The only debate so far is punctuation — how many brackets and question marks one error message can carry.

The generics conversation is officially on hold until after 8.6 ships — which isn't stopping anyone. Henrik Skov wrote in asking for generics to be opt-in, worrying: "adding reified generics will just make it even slower." His sketch: type-erased generics hiding inside comment syntax, checked by IDE plugins or a C extension, with the engine substituting mixed at compile time. Holly Schilling's reply opened like a sermon: "Have you heard the good word of Monomorphized Generics? Performance matches standard typed code." And she restated the schedule — generics talk waits until September or October, so it doesn't bury the 8.6 release work — with her inbox open in the meantime.

Osama Aldemeery's PREG_THROW_ON_ERROR RFC got its first real design review. Bernard Scharp asked whether compile failures and runtime failures deserve separate exception classes. Rowan Tommins supplied the rulebook: PHP's throwables policy says extension exceptions extend the extension's own base class, never the SPL ones. Osama's position is one PregException, with the door open — and he had a concrete reason: today, the useful detail of a compile failure lives only in the warning text, so a dedicated compilation exception "would carry "Internal error" and little else". That connects to Christian Schneider's other catch: under the flag, a bad pattern raises both the warning and the exception. Osama confirmed it, and defended it as the honest trade — the warning is where the detail is — while agreeing that "exception-instead-of-warning is the cleaner end state" once the exception can carry that detail itself.

Quick hits. Thursday was patch day: security releases landed across 4 branches at once — 8.2.33, 8.3.33, 8.4.24, and 8.5.9 — upgrade when you can. The same day brought PHP 8.6.0alpha3, an early test release. And the 8.6 release managers posted the formal 1-week warning: the soft freeze hits when the beta 1 tag is created next Tuesday, August 11, beta 1 itself lands Thursday the 13th, every 8.6 RFC vote must be closed before then, and the hard freeze follows at RC 1 on September 22.

So that's the week: the 35-ballot deprecation vote closes Monday with list() deadlocked and let balanced exactly on the 2/3 line; a function-autoloading vote opened and was pulled inside a day — the 2nd author in 2 weeks to stop his own ballot over the process rules; literal types bowed out of 8.6 on its own terms; Duration and the minimum-versions RFC are officially in; pipe assignment has a week to find its two-thirds; and the freeze arrives Tuesday. 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.

youtube.com
u/ProjektGopher — 15 days ago
▲ 27 r/symfony+2 crossposts

This Week In PHP Internals | July 29, 2026

While the Internals list is not technically directly Symfony related, it does affect every single one of us.

Hello world, from Laracon US 2026 in Boston — it's Wednesday, July 29, 2026, and here's what happened This Week in PHP Internals.

15 stories this week, so let's get into it. But first, This week's episode is brought to you by Tideways. When a request is slow and your logs won't say why, Tideways shows you where the time went — profiling, tracing, and monitoring built specifically for PHP. Slow request to root cause, in minutes. Setup takes 5 minutes, no credit card required. Start your free trial at tideways.com. And we have a second sponsor this week — Geocodio: address correction, geocoding, data enrichment, and distance calculations for North America and the UK. Built on Laravel since 2014. Try it free at geocod.io.

This week's top story: the mass deprecation vote for PHP 8.6 is open. Gina P. Banyard opened it Monday, and it's 35 separate ballots, each needing its own 2/3 majority — and each submitted individually, because as Gina reminded everyone, the wiki can only handle one vote at a time. Voting runs through August 10, and most of the 35 are passing easily — mysqli_get_charset() stands at 34 to nothing, and spl_classes() at 33 to nothing. But the headliners are moving the other way. list() — the construct Juliette Reinders Folmer's Packagist scan found over twelve thousand times — stands at 17 yes to 19 no, falling well below the required two-thirds threshold. The gettext _() alias is failing at 6 to 18. Reserving in, out, and inout is failing at 5 to 16, with 13 abstentions. And let sits at 17 to 10 — a majority, but still shy of 2/3.

The loudest argument is about one of the smallest items: the dechunk stream filter, which as of recording sits at 15 yes to 13 no — a coin-flip vote on a 2/3 question. On Monday, Matteo Beccati was the only no vote, and he explained why, warning: "I believe we should provide such an alternative together with the deprecation," rather than expecting projects with 200-million-plus installations — he names symfony/http-client — to write their own decoder in PHP. Jakub Zelenka agreed the item wasn't ready, saying it "should wait till it's properly investigated." Pierre Joye ran his own usage research and pushed back, noting: "Being present in a code base does not automatically mean it is used" — Symfony's native client disables the filter by default, and most stacks sit on curl anyway. Matteo then corrected the research: Symfony has shipped a pure-PHP alternative since release 8.2, which is exactly why Pierre's search pointed the wrong way. Jakub's objection sharpened from there, and he wrote: "This is exactly a half baked deprecation because we need to keep it for internal use anyway ... so this does not give us any code removal and we still need to maintain it. I don't understand why we need to rush it as there is no real reason for that." By Tuesday evening he'd also revealed a twist — he already fixed the select limitation on filtered streams in master, so that improvement lands in 8.6 no matter how this ballot goes. Kamil Tekiela, meanwhile, asked a different question — why deprecate define()'s dead case-insensitive flag at all, when just removing the parameter breaks nobody. So far, nobody has answered him.

Caleb White's pipe assignment operator, |>= — the compound form of the pipe, and his first RFC — went to ballot Tuesday morning, walked to the deadline with detailed coaching from Tim Düsterhus, whom Caleb thanked for "going to bat for this RFC". The machinery worked; the voters are split right down the middle — as of recording the count is 8 yes, 8 no, 3 abstaining, and it needs 2/3. Voting runs to August 11.

The queue from last week showed up on time. Nick Sdot opened voting on readonly property defaults Friday. It stands at 17 to nothing, with 5 abstentions — nobody's against it yet. That one closes August 7. And Khaled Alam opened voting Saturday on const object property writes — allowing writes to properties of objects referenced by constants. After a couple of quickly-fixed procedural stumbles, the count stands at 11 to 2, with 5 abstentions — above the 2/3 line. That one closes August 8.

Two carryover votes come off the board this week, and neither thread needed a single new email. The minimum-supported-versions vote for 8.6 closes Thursday. Requiring autoconf 2.71 stands at 27 to 2 — and notably, the no column shrank from 3 to 2 since last week. Requiring COM_RESET_CONNECTION stands at 26 to nothing. And the Time\Duration class closes Friday. The primary has stretched to 33 to 1, and full method names — multiplyBy, divideBy — lead the naming question 28 to 2. Barring a very strange 48 hours, PHP 8.6 gets a Duration class.

Seifeddine Gmati's literal scalar types made it to a ballot Thursday morning — for 18 minutes. At 5:26 UTC he opened the vote, 3 questions deep: integer and string literals, float literals, and strict-versus-coercive matching. At 5:44 he pulled it back down, writing: "I am retracting this vote: I opened it prematurely, in violation of the voting prerequisites in the Feature Proposals policy." No intent-to-vote 2 days ahead — and that morning's 1.0 update was a minor change, which starts a 7-day cooldown. He plans to reopen tomorrow, July 30 — a date that brushes right up against the freeze, so it may yet retarget 8.7. The self-retraction turned into a referendum on the process itself. Juris Evertovskis — a longtime reader and one-time RFC author who says he never felt "internal enough" to comment on the process — decided to comment on the process: "All the mandatory cooldowns, cooldown resets on minor changes, announcements to vote, cooldown resets on inactive discussions appears to me like bureaucratic hoops that people have to jump through. The process was hard and daunting enough before this." Bob Weinand agreed, noting he voted against the process RFC back then, and framed the trade plainly: "You sort of have to decide what you optimize for - easier for authors, or easier for commenters. But I think in this case it went way overboard in terms of strictness."

The gd 2.4 timing dispute from last week wound down to closing statements, and they were constructive ones. Pierre Joye's position: the late arrival was unavoidable — the libgd sync had to survive PHP's full CI matrix first — and he argued: "Process has to be humane ... If they are purely for the sake of having a process, we fail as a project and solve users' needs." Rowan Tommins made the case that this isn't red tape but triage: "There are maybe twenty sections describing details of the proposal, and the crude [reading-time] estimate in Firefox is 47-60 minutes. It may be clear in your head that most of this is uncontroversial, but for anyone else to even make that judgement requires investing a reasonable amount of time." Better, he says, to spend that time on 8.6 work now and this RFC after — though he left open whether the cut-off itself sits in the right place. One concrete footnote: Pierre added the procedural gd image functions to the deprecation path — on his telling, a warning from the gd extension itself in 8.7, and gone in PHP 9.

Derick Rethans hit a fresh regression on master: his Xdebug test suite started failing, and the trail led to the commit implementing the display-error-function-args RFC. Stream warnings from include, require, bzopen(), finfo_open() and friends no longer say which file couldn't be opened — the path was an argument, and arguments got scrubbed. Derick's verdict was blunt, arguing this "Doesn't seem to me like an enhanced for users" — either put the filename into the message text itself, or revert the change, RFC or not. Kamil Tekiela defended the new behavior, countering: "The file path could leak sensitive information". His suggestion runs the other direction — fold the path into all stream error messages deliberately, rather than leaking it by accident — and while he's at it, he'd rather streams stopped raising their own duplicate warnings entirely. With open_basedir in effect, one failed include currently earns you 3 warnings.

Edmond of the TrueAsync project turned last week's zero-reply pre-RFC into a real one: Concurrency Support in the PHP Engine. The pitch is deliberately minimal — give the engine a coroutine representation and make the scheduler pluggable by extensions. He was explicit about the shape of it, writing: "It adds no classes, no functions, no constants and no syntax: the engine compiles in no PHP symbols at all. With no scheduler registered, PHP behaves exactly as it does today." This is not True Async — it's the seam True Async would plug into, alongside anyone else. A scheduler can adopt fibers started by ReactPHP, Revolt, or AMPHP; there's per-coroutine storage that could someday make ob_start() coroutine-safe; and there is no parallelism — everything stays on one OS thread. The implementation already exists as a pull request. And this time he got a reply. Seifeddine Gmati expects the real discussion to wait until after 8.6 ships, but his early read was warm: "Overall, I really like this idea and approach. I think this is the right path forward." Edmond's answer: no rush.

Osama Aldemeery — who got his RFC karma in 2 minutes flat last week — shipped the RFC: PREG_THROW_ON_ERROR. Pass the flag to any preg_*() call and a PCRE failure throws a catchable PregException, instead of a warning plus a false or null you have to notice and then chase through preg_last_error(). It's the same pattern JSON_THROW_ON_ERROR already set, and it's strictly opt-in. He stressed the conservatism, writing: "A call does exactly the same thing with it or without it, byte for byte" — the flag only changes how the error is delivered. It targets the release after 8.6, and he's aware of Larry Garfield's request to hold non-8.6 business until September — his compromise is to let the thread tick over quietly rather than restart it. So far it has 0 replies.

Quick hits. The 8.6 release managers posted the 2-week warning: beta 1 lands Thursday, August 13, the soft freeze hits when the tag is created August 11, and every RFC vote targeting 8.6 must be closed before beta 1 — after that, merges need release-manager approval until the hard freeze at RC 1 on September 22. The CURLOPT_HTTPHEADER newline thread came back with a verdict from upstream: Sjoerd Langkemper relayed word from curl's own Daniel Stenberg that the docs already say headers "must not be CRLF-terminated" and libcurl may start rejecting the stragglers outright — there's a curl pull request in flight. Matteo Beccati's conclusion was to stand down, saying: "libcurl will eventually take care of it." And Steven Wilton's snmp extension work is back at the finish line — both reworked PRs updated per Gina P. Banyard's review, awaiting a final squash-and-merge check, with a third PR queued behind them.

The PEAR decay story found a new symptom: Juliette Reinders Folmer reports that individual bug pages on the PEAR site now error out claiming the original reporter "has not yet confirmed their email address" — which locks away exactly the archaeology she'd argued is worth preserving. And the typed-arrays thread got its epilogue: Larry Garfield explained why PHP probably won't get new base types for collections — the engine makes that "really really hard", which is the same reason enums became objects — shared his and Derick Rethans's old collections research notes, and set the course: wait for reified generics, then convene a working group. Holly Schilling's counter-offer was to skip the wait, pointing everyone at her self-published PHP 9 roadmap — generics, structs, modules, extensions, and surfaces — which she'd like the list to treat "as a rough outline for the future."

So that's the week: 42 ballots open at once — the 35 deprecations, with list() headed for defeat and dechunk splitting the room; pipe assignment dead even out of the gate; readonly defaults and const writes both comfortably clear; Duration and minimum versions closing within days, both far ahead; a literal-types vote that lasted 18 minutes and reopens tomorrow; and the soft freeze 2 weeks out. Links to every thread are below. Thanks again to Tideways.com and Geocod.io for supporting this week's episode. We're Artisan Build. See you next week.

youtube.com
u/ProjektGopher — 19 days ago
▲ 41 r/symfony+2 crossposts

This Week In PHP Internals | July 22, 2026

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

20 stories this week, so let's get into it. But first, This week's episode is brought to you by Tideways. Slow requests, and no clear reason why? Tideways helps you understand exactly where your PHP application spends its time — profiling, tracing, and monitoring to find and fix bottlenecks faster. And your profiling data stays hosted in Germany — GDPR-friendly by default. Learn more at tideways.com.

This week's top story: the season's first ballots are open — 2 sets of them — and the early counts are lopsided. Tim Düsterhus opened voting on the Time\Duration class on Friday with 2 ballots: a primary, needing a 2/3 majority, and a secondary choosing between full and abbreviated method names. As of recording, the primary stands at 23 to 1, and full names lead 18 to 1 — so multiplyBy and divideBy, not mul and divBy. Voting closes July 31. And remember Pierre Joye, who last week was leaning no over fromSeconds() and its capped nanoseconds argument? This week he closed the loop and voted yes, writing: "We were like ships passing in the night for some of my disagreements. The RFC wiki page did not show the additional constructor for other units, which hence the inconsistency I pointed out for the extra [nanoseconds] argument in fromSecond. They are here, and reduce this down to a lower level of bad APIs, more a pragmatic compromise conciliating different (if not numerous) use cases. Anything can be perfect, or shipped. Choose one." It turns out the per-unit constructors that resolved his objection had been in the RFC all along. His ballot almost didn't register, though — each vote on the wiki is a separate form, and Tim had to point out that you submit each one individually. The count now includes him.

Before the ballots opened, the Duration thread picked up a subplot about PHP 9. Holly Schilling — who wrote the class-extensions RFCs we covered last week — announced she's drafting a Value Structs proposal for after the 8.6 window, and argued that Duration would make a better struct than a class, with both ideally landing together in PHP 9. Ilija Tovilo replied by linking his own existing structs-v2 draft and asking whether she was aware of it. She was — she'd read it before drafting her own, and diverged from it on purpose, keeping mutating and non-mutating functionality separate. Tim saw no reason to wait on any of this, saying a draft-stage idea "will take an unknown duration to land - if it ever happens" — his pun, not mine — and that improvements to the standard library shouldn't queue behind it.

The week's other live vote came from Eric Norris, who opened balloting Thursday on minimum supported versions for PHP 8.6 — also with 2 questions, each needing a 2/3 vote. Requiring autoconf 2.71 for builds from git stands at 20 to 3 with 4 abstentions. Requiring COM_RESET_CONNECTION — which sets a floor of MySQL 5.7.3 or MariaDB 10.2.4, so persistent connections actually get reset — stands at 21 to nothing with 3 abstentions. Alexander Kurilo arrived after the discussion phase to ask for an opt-in instead, warning that on older databases persistent connections will silently turn non-persistent. Eric noted: "MySQL 5.7.3 is at least a decade old; it was released on December 3rd, 2013." After walking through every opt-out design he could think of, he concluded the right move is to make the correct behavior the default. The 3 no votes on autoconf include Jakub Zelenka, who's worried about building on Red Hat Enterprise Linux 8 and 9 — Tim offered to delay that particular merge to early 8.7. Both votes close July 30.

Saturday night, Pierre Joye opened the RFC that grew out of the libgd sync we covered last week: gd 2.4. It's big — 3 pillars. First, syncing the bundled gd extension with upstream libgd: new codecs like QOI, JPEG XL, and UltraHDR, animated GIF and WebP support, multi-page TIFF, and real metadata handling. Second, an additive object-oriented Gd\ API — codecs with fromFile() and toStream(), immutable image info, streaming readers and writers. Third, a brand-new 2D vector canvas built on FreeType's rasterizer, with gradients and the full Cairo compositing set. He says the implementation is nearly done, including a security audit. He declared discussion open for 14 days, until August 1 — and that one sentence is where the trouble started.

Because August 1 plus a 14-day vote lands after the deadline. Release manager Matteo Beccati was gentle about it, writing: "As much as I like this RFC, I'm afraid it came in a little too late." Jakub Zelenka explained that nobody — release managers included — has the authority to grant an exception; that would take a change to the policy itself. And Rowan Tommins did the arithmetic: with alpha 1 out July 2, the cutoff for an RFC's final state was July 14, which is 4 days before this thread even opened. Pierre's frustration has a specific shape. The implementation was finished weeks ago — what delayed everything was that his pull request sat waiting on an approval that had been assigned to an automated bot reviewer, so no human was ever going to sign off, and he eventually merged it himself. He also argues the stakes are real, because PHP 9 is the one chance to change old defaults, and missing this window locks the current design in for years. The thread got tense over tone along the way — Pierre felt brushed off by a terse reply, and Rowan apologized outright, then made the counter-case that a fixed cutoff applied to everyone is fairer than debating each RFC's merits one at a time. All of this landed the same day Larry Garfield asked the list, in a separate thread, to hold new business until September 1 so reviewers can focus on 8.6's finish line. So gd 2.4 is alive and under discussion — just aimed at the next release, whatever its number turns out to be.

Caleb White's pipe assignment operator, |>=, had a crowded week. Larry Garfield opened it unable to find a compelling use case, and by Monday had moved to a no — pushed there, he says, by a competing proposal. That competing proposal is Vadim Dvorovenko's left-to-right assignment RFC, published Sunday, which claims the same |>= token with opposite semantics. Vadim objects on principle, arguing: "Attempting to transform such an operator from an immutable, functional construct into a mutable, imperative one steers the language in the wrong direction and undoes previous efforts." Caleb declined to merge the proposals, noting that F#, Elixir, OCaml, and Hack all kept ordinary assignment alongside their pipes. Larry also claimed none of the pipe proposals could make 8.6, and Tim Düsterhus corrected him, asserting: "This is false" — the last major change was July 13, so voting could open July 27 and close August 10, before the freeze. Meanwhile Bob Weinand asked whether the desugaring double-fires property hooks. Caleb came back with tests showing |>= behaves exactly like ??=, and updated the RFC's single-evaluation section to match. Vadim's own RFC, as of recording, has 0 replies.

Paul M. Jones's strict-namespace RFC — the piece he carved out of function autoloading last Tuesday night — spent its first full week in one long argument about a single word. Rowan Tommins objected first, writing that strict "implies some extra check that namespaces are [correct] in some way, which isn't really what this is about." Ilija Tovilo went deeper, arguing: "the value-add of this declaration is very small if the plan isn't ever to deprecate/remove the old behavior." Tim Düsterhus is in favor — with a rename to global_fallback=0. By Friday Paul had 4 candidate names on the table and a diagnosis: the pushback is the name, not the feature. Theodore Brown pointed out he'd floated the same directive in 2019; Paul added it to the prior art with an apology. And Benjamin Außenhofer suggested splitting the ballot — vote the concept, then vote the name. Rowan warned against it, writing: "a split vote leaves voters who actively dislike a particular name with an awkward choice: vote Yes, and risk the [bad] name being chosen; or vote No, even though you would support the feature under a different name." The rest of the autoloading corner kept moving too: Paul updated function autoloading mark 5 to lean on the new RFC and wants its vote open in about 2 weeks, and Michael Morris's improved-autoloading draft drew warm-but-firm feedback from Larry Garfield and Rowan Tommins — both like the namespace-setup-file idea, neither wants it crammed into the class autoloader's callback.

Nicolas Grekas didn't let Ilija Tovilo's "sadly not in favor" be the last word on serializable closures. His rebuttal: caching one attribute isn't the point — the point is skipping the entire metadata pipeline that frameworks re-run on every request, and that's the measured slow path. On the security design, he refused to loosen it, writing: "Name-based closure unserialization would ship a universal, app-independent gadget in the engine ... I won't commit to an RFC that turns every serialized payload into that kind of gadget, and I don't think we should, either." Then Saturday brought version 0.3, and a surgical cut — the reflection API is gone, the serialize() support stays. His reasoning: "serialize() is the one feature that most/all cache systems are built on, so that's the place that needs the improvement." Fresh reviews welcome.

Wendell Adriel came back to the list Thursday proposing typed array declarationsarray<int, string> as real syntax, with 3 escalating enforcement levels. The review was fast and unsparing. Lazare Inepologlou flagged that you can't soundly subtype a mutable array without splitting reads from writes, and Wendell shipped a revised draft the next day. Rob Landers warned the whole thing overlaps the reified generics work, on hold until after the freeze, which is late August at the earliest. Rowan Tommins noted that level 1 — syntax without enforcement — rhymes with the bound-erased generics RFC the list just declined. Michał Marcin Brzuchalski even found a runtime hole, where functions like parse_str() that build results directly into a typed property can dodge the check. By Monday, Wendell put the RFC on hold himself. Larry Garfield's verdict was the sharpest, calling this "the already-dangerously-overloaded array mega-type" and asking for real typed list, set, and dictionary objects instead — which Wendell promptly volunteered to help build.

The frozen deprecations list for PHP 8.6 got its evidence file. Juliette Reinders Folmer scanned the Packagist Top 4-thousand — nearly four hundred fifty thousand files — and posted counts for every proposal. The headline being: list() appears over twelve thousand times, and Juliette wrote plainly: "Having said that, I'm definitely not in favour of deprecating list()." Compare spl_object_hash() at 625, is_integer() at 303, and a long tail of single and double digits — several proposals scored a clean 0. Kamil Tekiela discovered his mysqli proposal had missed the procedural mysqli_stmt_init(), patched the text, and worried aloud: "I hope this change is not going to reset the counter." Tim Düsterhus was quick to correct the record downward — one scary-looking count, on _ as a constant, collapses to 0 once false positives come out. And Monday, right on schedule, Gina P. Banyard confirmed the timetable, writing: "I intend to open the vote next Monday (the 27th of July) for 2 weeks so that the vote is finished on time for 8.6." Every deprecation gets voted in isolation — bring a lunch.

Quick hits. Go Kudo returned with a rebuilt cache proposal — a bundled user_cache extension, fully decoupled from OPcache this time; Larry Garfield likes it, flagged the lock story around remember(), and gently redirected it to 8.7 — adding: "Or 9, if that's what we call it." Holly Schilling's 4x fix for non-public asymmetric setters got its answer: no RFC needed — Tim confirmed a pure performance improvement just needs PR review, and Ilia Alshanetsky called it "definitely a strong candidate for PHP 8.6 inclusion." fennic pitched engine-native PSR-4 autoloading with spl_autoload_psr4_register(); Alex Rock wants classmap support before it can replace Composer's bootstrap, and Heinz Wiesinger pointed to his existing PECL extension doing much the same. Edmond of the TrueAsync project published a pre-RFC for an async scheduler engine interface — coroutine-aware core, no scheduler in core itself. His philosophical problem is that the RFC has no user-visible changes at all, and so far it has 0 replies. And Osama Aldemeery asked for RFC karma to formalize PREG_THROW_ON_ERROR — Ilija Tovilo granted it 2 minutes later.

Liam Hammett's markup expressions thread sprouted an alternative: Edmond proposed making the parser extensible instead, so JSX-like syntaxes could ship as extensions — Morgan liked that better than blessing one syntax, and within a day Edmond had a working DSL-hooks prototype, announcing: "Your wish has been granted. 🙂" Máté Kocsis and Ignace Nyamagana Butera kept refining query parameters — the open question is whether parsing limits belong on builder methods too, with Ignace arguing PHP shouldn't police what's really a business constraint. Prateek Bhujel's terminal-helpers extension hit 0.6.0 — it's now installable via PIE, and its output methods now write to standard PHP streams like STDOUT and STDERR instead of only its own built-in targets. The ballot queue grew by 2: Nick Sdot posted intent to vote on readonly property defaults for on or around July 23, and Khaled Alam's const-object-property-write opens Saturday the 25th — both aiming ahead of the freeze. Ben Ramsey amended the Working Groups RFC with a new section setting expectations for charter-RFC discussion. And release week: PHP 8.6.0alpha2, 8.5.9RC1, and 8.4.24RC1 all shipped — with alpha 3 and both GA releases converging on July 30 — while the release managers posted the countdown that framed half of this episode: soft feature freeze August 11, beta 1 August 13, every 8.6 vote closed before then.

So that's the week: 2 ballot boxes open and both lopsided — Duration cruising at 23 to 1, minimum versions right behind it; gd 2.4 arriving 4 days after the door closed and pointing at the next release instead; a pipe operator with 2 authors claiming 1 token; typed arrays proposed, revised, and shelved inside 5 days; and the deprecations list armed with its evidence file, ballots opening Monday — with readonly defaults and const-property-write queued right behind. 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.

youtu.be
u/ProjektGopher — 29 days ago
▲ 32 r/symfony+2 crossposts

This Week In PHP Internals | July 15, 2026

While PHP Internals is not technically directly related to Symfony, internals does affect us all.


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 &lt;button&gt; 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, <Layuot /> fails loudly with a class-not-found error. With fallback resolution, it silently renders as a literal <Layuot> 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.

youtube.com
u/ProjektGopher — 1 month ago
▲ 36 r/symfony+2 crossposts

This Week In PHP Internals | July 8, 2026

While PHP Internals is not technically directly related to Laravel, internals does affect us all.


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

This week's episode is brought to you by Ballast. Your team ships constantly — but how much of that work actually lasts? Ballast reads your git history and computes a deterministic durability score: does shipped code hold up, or churn and get redone? Ballast is in early access now at ballast.now.

This week's top story is still Gina P. Banyard's Deprecations for PHP 8.6 — the annual bundle where every removal gets its own ballot — and this week it caught fire twice. First fire: the long-array question. With Seifeddine Gmati's list() deprecation already on the table, Tim Düsterhus floated a draft that turns array() into a real cast function — and Michael Morris erupted at where that road leads. He asked, "Are you crazy?" — deprecating array() would, by his math, touch 3 quarters of WordPress core and nearly every plugin. Seif's counter was all receipts: the rewrite is one ast-grep command, array(...) and [...] compile to byte-identical opcodes — and, for the record, "The proposal is to deprecate list(), not array()." Then Juliette Reinders Folmer — who maintains the WordPress Coding Standards — corrected everyone: WordPress still supports PHP 7.4, and short arrays were blocked there for years by a handful of core committers, not the community.

It got personal — Morris told Seif to step out of his ivory tower; Seif kept answering with engineering. He wrote: "I've written a compiler that migrated a multi-million-line codebase from one language to another, automatically, overnight. Swapping one AST node for another that is literally equivalent to the compiler is not a feat of engineering courage." To Morris's credit, when told he was turning it personal, he replied: "I am, and I apologize." — and the thread cooled.

Then Monday it reignited — over evidence. Gina regrouped the list, folded in new items sent to her directly, and set the clock: "If none are added or amended, I will initiate a call to vote next week." Rowan Tommins counted 35 proposals and only 8 with any discussion of who'd be affected, and threatened to cast 27 blanket no votes. Gina drew her line: "You are free to do as you please." — she won't produce metrics for the sake of metrics without an agreed method. Rowan held firm: "I do not think we should be removing features without thinking about who will be affected. I'm honestly shocked that that's a controversial opinion". Juliette, once again the bridge, renewed her offer to generate real impact data with PHPCompatibility — feasible, she says, for about 25 of the 36 items. One item is on its way out: the by-reference-return-modifier deprecation — Bob Weinand recommended a complete retraction, and its proposer had already offered one. The RFC freezes July 13 — expect the call to vote next week, though with the mandatory 14-day cooldown after Gina's latest changes, actual ballots open July 21 at the earliest.

Tim Düsterhus and Derick Rethans' Time\Duration class — the stopwatch value object aimed at 8.6 — got called done this week: "we would consider the RFC to be complete". The final decisions: add and sub won an informal PHP Foundation Slack poll unanimously; the past-tense method suffixes are gone; divideInto() got pushed to future scope; and the ban on negative constructor arguments stays, on Derick's call. One naming question goes to the voters as a secondary vote: full names like multiplyBy and absolute, or abbreviations like mul and abs — with the abbreviations needing a 2-thirds supermajority.

But one fight would not close: fromSeconds(). It takes seconds plus a nanoseconds argument, capped at 999 million 999 thousand 999 — overflow is rejected, not carried. Marc B. objected: "It makes it simple to reason about for you as implementing it - it forces the burden to the one using the API." Pierre Joye brought prior art: Java and Rust both carry the overflow instead of rejecting it, and JavaScript's Temporal doesn't impose the cap either. Tim's defense: an injective constructor means one value, one spelling — a form asking for seconds should reject out-of-range input the same way June 31 should be rejected, not silently become July 1. Neither side budged — and with the RFC complete, that question rides along to the vote.

Function autoloading now has 2 competing designs, and they met in the same inbox on the same day. Paul M. Jones updated his mark-5 RFC — that's attempt number 5 — adding a declare(strict_namespace=1) directive to kill the global-fallback edge case, plus research across the top 1000 Packagist packages: exactly 2 packages and 8 call sites would misbehave. Meanwhile, Michael Morris — fresh off the deprecations thread — had floated an idea on July 2, saying: "An idea that popped into my head an hour ago, that I don't have another PHP Dev to talk to about, what if you could register a function that is called by PHP the first time it sees a namespace declared?" Five days later that spitball was a formal draft: autoloader callbacks that take 2 arguments — the class and the namespace — firing the first time the engine meets a namespace. And within hours of Paul's update, Morris was in Paul's thread advertising his rival.

The reason the spitball grew legs is Rowan Tommins. His endorsement became the backbone of Morris's draft — he wrote: "This really nicely side-steps the global-vs-namespace sequence problem that function autoloading always runs into: by the time the engine reaches an unqualified name, the namespace loader has already run for the current namespace, and defined any functions it wants." Not everyone's sold. Aleksander Machniak flagged that passing null to existing string-typed autoloaders is itself a BC break, and Alex Rock argued the draft bundles 2 different proposals and called it overkill. Morris's reply had some edge: "And you've misread the proposal entirely."

The busiest brand-new thread: Matheus Martins revived typed closures — write Closure(int): bool as a parameter type, and a mismatched callback fails at the boundary with a clean TypeError instead of exploding deep inside your filter(). The reception was warm — Matthew Weier O'Phinney would find it "very useful", and Larry Garfield is in favor, to nobody's surprise. Rob Landers suggested waiting for generics; Seif pointed out that would need variadic generics, which have never appeared in any proposal — waiting for generics means waiting indefinitely. Larry was blunter: "Generics syntax is the wrong format to use for this, full stop." The real villain is the lexer: inside Closure(int), that (int) is a cast token. Osama Aldemeery, who's been down this exact tunnel, put it memorably: "So the natural spelling is, unfortunately, the engine-hostile one."

Where it landed: inline signatures first, named type-aliases later, and neither blocks the other. Larry pre-empted the objection everyone could see coming — if someone gets fussy about long signatures, the answer should be "that's nice, go work on aliases then and don't block this RFC". By Monday he'd added just one ask: invokable objects should fit through the same door, not get squeezed through closures.

Rob Landers' primary constructors — the constructor hoisted onto the class line — spent June fighting over whether it may carry a body. This week that fight hit its endgame, in a single day of posts. Rowan Tommins came off the fence — with a body bolted on, he'd be a definite no. Rob, the author, declined to relitigate: "All I can say is that I reject it for future scope, repeatedly." Nick Sdot stood down under protest, warning: "We don't need more half finished, half not working, confusing features in PHP." And then, quietly, the week's one unreserved fan — a reader who wrote that extending third-party classes and calling the parent constructor by hand "always felt dirty". The thread's been silent since July 1.

Michal Kral's scalar object methods(3)-&gt;pow(2), dispatched at compile time — came back for round 2, and the room steered it somewhere new. Michal gave real ground: he'd restrict or drop the file-order-dependent form, and lean on typed locals for safety. Seif stayed unmoved, arguing: "Seeing $s->trim() where $s is a string, I should know it works. A construct where identical AST dispatches or doesn't depending on file position, a redundant cast, or whether a declaration sits above or below the call is not something people can reason about." Then Larry Garfield reframed the whole conversation: a small curated set of methods, he said, "is bikeshed bait, and needlessly limiting" — and counter-pitched Kotlin-style extension functions on any type, from a design he drafted with Sara Golemon. Michal's response? Genuinely interested. They're talking off-list once Larry's back from vacation.

To the scoreboard — one ballot closed, one never opened. Jordi Kroon's third-party extension documentation RFC is in: 26 to 1, with 1 abstention. The secondaries settled too: the docs land on a php.net subpath rather than a new subdomain, 15 to 8, and the old user notes get dropped in the move, 21 to 4. Meanwhile the grapheme_mask vote that was announced for July 3? As far as we can tell, it never opened — the RFC page still says draft, and the feedback stayed kind but firm. Yuya Hamada wrote: "Thank you very much for your RFC. But move to voting phase is too fast." The pipeline ahead is stacked: deprecations expects its call to vote next week, and Duration finishes its cooldown just in time for the mid-August freeze.

Quick hits — and there are a lot, so this is a 2-slide round. July 2 was patch day: security releases for 8.2, 8.3, 8.4, and 8.5, and 8.6.0 alpha 1 is out for testing. Eric Norris and Tim Düsterhus published the minimum-supported-versions RFC — newer autoconf, and MySQL 5.7.3 or MariaDB 10.2.4 for persistent connections — and an anonymous tester promptly found a real connection leak on old MySQL, declaring: "There is connection leak here!" — Eric's tracked down the cause and is weighing a fix. Nicolas Grekas redesigned serializable closures and offered a slimmed-down fallback, nudging the list that 8.6 won't wait. Osama Aldemeery floated a PREG_THROW_ON_ERROR flag — implementation already built. And Nick Sdot posted a tiny RFC: default values on readonly properties, a 5-line removal — zero replies so far.

Still going. Literal scalar types turned into an enums-versus-literals standoff, where Nick warned: "We should not make PHP another TypeScript." Ben Ramsey added a Foundation-SIGs section to Working Groups and wants feedback before he votes it — or withdraws it. The DTLS experiment graduated to a working 1.2 branch; Jakub Zelenka wants a draft PR. Pierre Joye synced bundled GD with libgd 2.4 and is untangling Windows dependencies. Pratik Bhujel's terminal helpers got Derick's blessing — ship it via PIE, since PECL takes no new packages. And Pratik also asked whether fixing sscanf's %c whitespace bug — in place since PHP 4.3.2 — breaks anyone on master.

So that's the week: a deprecations list that fought about WordPress and then about evidence, with the call to vote days away; a Duration RFC wrapped up and waiting out its cooldown; 2 rival answers to function autoloading colliding in real time; typed closures winning the room while the lexer holds the door; and the one ballot that closed, passing 26 to 1. Links to every thread are below. We're Artisan Build. See you next week.

youtube.com
u/ProjektGopher — 1 month ago
▲ 26 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)-&gt;pow(2), or " hello "-&gt;trim()-&gt;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 — 2 months ago
▲ 36 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-&gt;add($dur2)like a civilized person. By Tuesday Tim had already renamed the ISO parser and added an -&gt;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, &lt;?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 — 2 months ago
▲ 34 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 `&lt;?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 `&lt;?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 &amp; 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 &amp; 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 — 2 months ago
▲ 26 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&lt;NotFound&gt;`, then `catch HttpError&lt;Forbidden&gt;`. 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 &lt;?php tag on trial]


Story two: the `&lt;?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 `&lt;?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 &amp; 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 — 2 months ago