<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Len Woodward</title>
    <description>The latest articles on DEV Community by Len Woodward (@projektgopher).</description>
    <link>https://dev.to/projektgopher</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1383734%2Ff5ede504-5ae0-422b-8d13-69b3bfd2a1a1.jpeg</url>
      <title>DEV Community: Len Woodward</title>
      <link>https://dev.to/projektgopher</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/projektgopher"/>
    <language>en</language>
    <item>
      <title>This Week in PHP Internals | Nov 5, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Thu, 05 Nov 2026 22:18:53 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-nov-5-2026-51p8</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-nov-5-2026-51p8</guid>
      <description>&lt;p&gt;This year, FrankenPHP fixed a session ID leaking to other clients, a use-after-free, and a double free. Each one, its creator says, came from state that wasn't reset between two requests. That's because, he says, PHP's engine can't tell when a request ends, if the same script serves the next one. He wants to change that.&lt;/p&gt;

&lt;p&gt;Hello world, it's Thursday, November 5, 2026, and here's what happened This Week in PHP Internals. 14 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;AI made building software easy, and owning it hard. Scalpels installs open source apps into your own Laravel Cloud or Forge account in one click, so your data never leaves your infrastructure. The &lt;a href="https://scalpels.app/pricing" rel="noopener noreferrer"&gt;Free plan&lt;/a&gt; is zero dollars, forever, and new Laravel Cloud accounts get ten dollars in credit. Get started at &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;scalpels.app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Corrections (00:56)
&lt;/h2&gt;

&lt;p&gt;A few corrections from last week, most of them from Tim Düsterhus. On the CSV extension, Tim didn't ask Damian to wait until after the security release. The release had just happened, so people were likely busy patching their servers and hadn't caught up on the list, and he suggested waiting until things calmed down. And on calling extension methods without parentheses, we missed Rowan Tommins's main point. He wrote: "It also seems odd to propose it now, as an extension to something that doesn't even exist yet."&lt;/p&gt;

&lt;p&gt;Tim also caught two in last week's top story and quick hits. In Brian Nguyen's quote, "not deprecating integer" means the &lt;code&gt;(integer)&lt;/code&gt; cast, which PHP just deprecated. And I said Sjoerd "postponed" &lt;code&gt;openssl_get_channel_binding&lt;/code&gt;. He proposed it, and it was brand new. Thanks, Tim.&lt;/p&gt;

&lt;p&gt;And a viewer on Bluesky pointed out that Brian's first mail said "I am not proposing freezing features or cosmetic deprecations." That's right. The embargo was in his second thread, the next morning, and our social posts skipped that distinction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132937" rel="noopener noreferrer"&gt;Tim Düsterhus on the CSV extension vote timing&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132915" rel="noopener noreferrer"&gt;Rowan Tommins on paren-less extension methods&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132917" rel="noopener noreferrer"&gt;Brian Nguyen's first mail&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132920" rel="noopener noreferrer"&gt;Brian Nguyen's second mail&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Request Hooks (02:08)
&lt;/h2&gt;

&lt;p&gt;This week's top story: Kévin Dunglas, who created FrankenPHP, wants PHP's engine to know when a request ends. In worker mode, one long-running script handles request after request, keeping things like the Composer autoloader and framework services in memory. Symfony, Laravel and Yii support it natively. But the engine doesn't know, so FrankenPHP resets each request's leftovers by reaching into PHP's internals, which he calls fragile. He wrote: "Each omission results in a cross-request leak or a memory safety bug."&lt;/p&gt;

&lt;p&gt;So he proposed two optional hooks, request end and request begin, that a worker-mode server calls between requests, so each extension resets its own state. Servers that don't call them see no change. After talking it through with Tim Düsterhus, he narrowed the rule to state built from the incoming request, and he's writing a short RFC.&lt;/p&gt;

&lt;p&gt;Pierre asked whether last week's Scope RFC already covers this, and Larry Garfield asked how the two lifetimes would stay in sync. Kévin's answer: a scope gives a request an identity, but no clear end. So request begin would create the scope, and request end fires when the response is done, even if the scope lives on. He wrote: "The user-space and engine-space lifetimes stay in sync because the SAPI drives both."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132960" rel="noopener noreferrer"&gt;Kévin Dunglas, the proposal&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132976" rel="noopener noreferrer"&gt;Narrowed after review&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132978" rel="noopener noreferrer"&gt;How it works with Scope&lt;/a&gt; · &lt;a href="https://github.com/dunglas/php-src/tree/request-boundary-hooks" rel="noopener noreferrer"&gt;Draft patch&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bcrypt Wrap (03:36)
&lt;/h2&gt;

&lt;p&gt;bcrypt only reads the first 72 bytes of a password, and now there are two RFCs to fix it. Andrey Andreev opened the second one this week, &lt;em&gt;the alternative he asked for time to finish&lt;/em&gt;. &lt;code&gt;PASSWORD_BCRYPT_WRAP&lt;/code&gt; hashes the password first, with cSHAKE256 by default or HMAC-SHA512, then runs bcrypt on the result. The RFC says that removes bcrypt's length and null byte limits.&lt;/p&gt;

&lt;p&gt;Kamil Tekiela objected that it shrinks bcrypt's input space and is open to hash shucking. Andrey replied that a prehash doesn't reduce bcrypt's security or input space, and that his salts keep the prehash separate from a plain hash. Tim Düsterhus asked for pseudo-code to settle it, and Andrey added it to the RFC on Monday.&lt;/p&gt;

&lt;p&gt;Sjoerd Langkemper, who wrote the other RFC, compared the two. His uses the same algorithm as Python's passlib and adds less code. Andrey's supports two prehashes in the PHC string format. Sjoerd thinks both are secure enough, and that one new algorithm is enough. He wrote: "It is unfortunate that we now have two RFCs that are so similar. Voting on them in isolation could result in an undesirable outcome." Andrey replied: "It just turned out this way, hopefully we don't have to look at it as mine against yours."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/password_bcrypt_wrap" rel="noopener noreferrer"&gt;RFC: Add PASSWORD_BCRYPT_WRAP&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/bcrypt_sha256" rel="noopener noreferrer"&gt;RFC: PASSWORD_BCRYPT_SHA256&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132982" rel="noopener noreferrer"&gt;Sjoerd Langkemper's comparison&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope RFC (05:00)
&lt;/h2&gt;

&lt;p&gt;Larry Garfield is sold on the use case for Frode Børli's Scope RFC, but he's worried about code that doesn't know it's running inside a scope. A new scope starts with empty superglobals, so a legacy function that reads &lt;code&gt;$_GET&lt;/code&gt;, called 20 functions deep, quietly stops working. He'd rather a new scope start from a clone of its parent's.&lt;/p&gt;

&lt;p&gt;He also expects everyone to hand-write WeakMap code to keep state per scope, and floated a &lt;code&gt;Scoped&lt;/code&gt; attribute to automate it. In his own example, he forgot to initialize the WeakMap. He wrote: "So this is a pattern we need to work to make as fool-proof as possible, because we're all fools." &lt;em&gt;No lies detected.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Rowan Tommins welcomed a focused RFC that adds only what userland can't do, shared the WeakMap worry, and asked whether "context" would be a clearer name. Frode is keeping Scope, and says the WeakMap pattern takes getting used to, but isn't hard. He hasn't answered Larry yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/scope" rel="noopener noreferrer"&gt;RFC: Scope&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132952" rel="noopener noreferrer"&gt;Larry Garfield&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132983" rel="noopener noreferrer"&gt;Rowan Tommins&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132984" rel="noopener noreferrer"&gt;Frode Børli&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Time Instant (06:08)
&lt;/h2&gt;

&lt;p&gt;PHP's next date and time class would have no timezone at all. Tim Düsterhus and Derick Rethans's &lt;code&gt;Time\Instant&lt;/code&gt; RFC is a point in time, and a clock returns one. Back after the security releases, Tim answered a reviewer's 15 points and kept the core design: the clock returns an Instant, not a date in some timezone. He wrote: "The timezone is a presentation-layer concern and stuff you 'present' to the user is generally expected to be coming from the database, rather than coming from the clock."&lt;/p&gt;

&lt;p&gt;He also turned down a raw Unix timestamp shortcut, to keep the API well-typed. The system clock can no longer be serialized, and two ideas moved to future scope: exposing the clock's resolution, and a faster, coarser system clock. There's no implementation pull request yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/time_instant_class" rel="noopener noreferrer"&gt;RFC: Time\Instant and Time\Clock&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132953" rel="noopener noreferrer"&gt;Tim Düsterhus's answers to the review&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132999" rel="noopener noreferrer"&gt;follow-up&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON Comments (07:03)
&lt;/h2&gt;

&lt;p&gt;Comments and trailing commas in JSON were about to go to a vote. Otar Chekurishvili's RFC adds two opt-in flags for &lt;code&gt;json_decode&lt;/code&gt; and &lt;code&gt;json_validate&lt;/code&gt;, strict JSON stays the default, and Larry Garfield had no objections left.&lt;/p&gt;

&lt;p&gt;The vote was planned for Monday. Then Jakub Zelenka commented on the pull request: "I personally don't like non standard additions as they might complicate future optimizations in the parser." So Otar postponed the vote, the morning it was due to open.&lt;/p&gt;

&lt;p&gt;He replied on the pull request that both flags are opt-in, and a future fast parser could handle strict JSON and fall back when a flag is set. In strict mode, the change costs about 1.6% more CPU instructions, or 0.6% with a small scanner change. He'll answer the concern in the RFC, then announce a new vote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/json_comments_trailing_commas" rel="noopener noreferrer"&gt;RFC: JSON comments and trailing commas&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132988" rel="noopener noreferrer"&gt;Vote postponed&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23336" rel="noopener noreferrer"&gt;The pull request discussion&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Votes (08:00)
&lt;/h2&gt;

&lt;p&gt;Two votes closed this week, and one opened. Sjoerd Langkemper's RFC passed 27 to 1, so in PHP 8.7, &lt;code&gt;hexdec&lt;/code&gt;, &lt;code&gt;octdec&lt;/code&gt;, &lt;code&gt;bindec&lt;/code&gt; and &lt;code&gt;base_convert&lt;/code&gt; throw on invalid characters instead of quietly ignoring them. Muhammed Arshid's &lt;code&gt;Filter&lt;/code&gt; enums were declined, 2 to 16, with 2 abstentions. And Weilin Du's vote to let &lt;code&gt;ini_get_all&lt;/code&gt; accept extension names in any case is at 12 to 0, with 2 abstentions. It closes November 16th.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/throw_error_for_invalid_characters_for_number_base" rel="noopener noreferrer"&gt;Throw exception for invalid characters in number base functions (accepted 27–1)&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/invalid_filter_options" rel="noopener noreferrer"&gt;Add Filter\Filter and Filter\Flag Enums (declined 2–16–2)&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/case_insensitive_ini_get_all" rel="noopener noreferrer"&gt;Case-insensitive extension names in ini_get_all() (open until Nov 16)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Hits (08:35)
&lt;/h2&gt;

&lt;p&gt;Quick hits. Ignace Nyamagana Butera likes the direction of the CSV extension, but says major points are unsolved: the top-level namespace, the lax and strict naming, and leaning on RFC 4180, which isn't an accepted standard. He suggests calling it Character Separated Value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/csv_extension" rel="noopener noreferrer"&gt;CSV extension RFC&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132957" rel="noopener noreferrer"&gt;Ignace Nyamagana Butera&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For binary parameters in PDO, Ilia Alshanetsky and Calvin Buckley now lean toward a flag instead of a new type, which would break drivers until each one updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/pdo_binary" rel="noopener noreferrer"&gt;PDO binary parameters RFC&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132985" rel="noopener noreferrer"&gt;Ilia Alshanetsky&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132992" rel="noopener noreferrer"&gt;Calvin Buckley&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sjoerd's &lt;code&gt;openssl_get_channel_binding&lt;/code&gt; now throws an exception instead of returning null, answering Tim's question from last week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/openssl_get_channel_binding" rel="noopener noreferrer"&gt;openssl_get_channel_binding() RFC&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132993" rel="noopener noreferrer"&gt;Sjoerd Langkemper's update&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Xavier Leune wants SSRF protection in &lt;code&gt;curl&lt;/code&gt; first, so it lands in PHP 8.7, and maybe streams in a later RFC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132955" rel="noopener noreferrer"&gt;Xavier Leune on SSRF protection in curl&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23657" rel="noopener noreferrer"&gt;php-src #23657&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Chris Abner Herrera Navarro went from a karma request to an RFC for &lt;code&gt;grapheme_str_pad&lt;/code&gt; in under a week. It pads text by the characters you actually see, and Tim said it has exactly what he expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/grapheme_str_pad" rel="noopener noreferrer"&gt;grapheme_str_pad() RFC&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/25179" rel="noopener noreferrer"&gt;php-src #25179&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Máté Kocsis's query parameters RFC, Tim Düsterhus checked with the security team, and says a long query string can't make memory grow faster than the input, and the parameter count is already capped, so a separate length limit isn't needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/133001" rel="noopener noreferrer"&gt;Tim Düsterhus on the query string length limit&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/query_params" rel="noopener noreferrer"&gt;Query parameters RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Artem Ukrainskiy got karma for an RFC on multi-pattern search and replace, with &lt;code&gt;Str\Matcher&lt;/code&gt; and &lt;code&gt;Str\Replacer&lt;/code&gt; classes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132981" rel="noopener noreferrer"&gt;Str\Matcher and Str\Replacer (draft)&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/25122" rel="noopener noreferrer"&gt;php-src #25122&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And Andrey Andreev listed five oddities in the password hashing functions, with a plan to fix them over the next few months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132998" rel="noopener noreferrer"&gt;Password hashing API&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (10:16)
&lt;/h2&gt;

&lt;p&gt;So that's the week. Kévin Dunglas proposed hooks so PHP knows when a request ends in worker mode, and showed how they'd work with Scope. There are now two bcrypt fixes side by side, and Sjoerd says one is enough. Larry pushed back on Scope's empty superglobals, Tim kept the core of &lt;code&gt;Time\Instant&lt;/code&gt;, and the JSON comments vote is on hold. Number base exceptions passed, and &lt;code&gt;Filter&lt;/code&gt; enums didn't. Links below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://thephp.foundation" rel="noopener noreferrer"&gt;The PHP Foundation&lt;/a&gt; funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;a href="https://opencollective.com/phpfoundation" rel="noopener noreferrer"&gt;opencollective.com/phpfoundation&lt;/a&gt; — or try guilting your employer into it.&lt;/p&gt;

&lt;p&gt;If you found this useful, a like or a comment helps more people find it. And if you missed &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-oct-29-2026-1m75"&gt;last week's episode&lt;/a&gt;, where a call to freeze PHP until it has a formal spec got an answer about money, that's a good one to watch next. Thanks again to &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;Scalpels.app&lt;/a&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week in PHP Internals | Oct 29, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Thu, 29 Oct 2026 21:33:21 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-oct-29-2026-1m75</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-oct-29-2026-1m75</guid>
      <description>&lt;p&gt;A week after two critical bugs in PHP's own engine, someone asked the internals list to stop. No new features and no cosmetic deprecations, until PHP has a formal spec and four independent implementations, written in formal-methods frameworks. Four people who work on PHP replied. One of them called fixing PHP's bugs a money problem.&lt;/p&gt;

&lt;p&gt;Hello world, it's Thursday, October 29, 2026, and here's what happened This Week in PHP Internals. 15 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;AI made building software easy, and owning it hard. Scalpels installs open source apps into your own Laravel Cloud or Forge account in one click, so your data never leaves your infrastructure. There are &lt;a href="https://scalpels.app/products" rel="noopener noreferrer"&gt;15 apps in the catalog&lt;/a&gt;, from a private Composer registry to a mail trap for staging. The Free plan is zero dollars, forever, and Laravel bills you directly for the hosting. There's even a guide to patching PHP on your own servers. Scalpels launches this Saturday, October 31st, at &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;scalpels.app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spec Debate (01:21)
&lt;/h2&gt;

&lt;p&gt;This week's top story: after last week's emergency releases, Brian Nguyen argued that PHP's two critical bugs show the cost of having no formal specification and only one implementation. He proposed a living spec of the bytecode and the parser, executable semantics in research frameworks like K and PLT Redex, and testing any second runtime against WordPress, Laravel and Symfony. His first mail said it was not an embargo. The next morning, he opened a second thread asking for one, until four formal implementations exist. He wrote: "Not adding a feature cannot break apps. Not deprecating (integer) cannot break apps. A corrupt allocator can."&lt;/p&gt;

&lt;p&gt;Rowan Tommins doubted a spec would have helped, since memory management is exactly what differs between implementations. And on .NET, he pointed out that if 0.01% of Microsoft's roughly 200,000 employees work on it full time, that's still twice as many as have ever been paid to work full time on PHP. Sjoerd Langkemper wrote: "I think PHP is not starved for bugs. The bottleneck is bugfixes." And Larry Garfield wrote: "This is a money problem, just like most major OSS projects. It's nothing more complicated than that."&lt;/p&gt;

&lt;p&gt;His fix is to get PHP-using companies to become significant &lt;a href="https://thephp.foundation" rel="noopener noreferrer"&gt;PHP Foundation&lt;/a&gt; sponsors, or to put their own employees on PHP full time. Ben Ramsey asked whether Brian wanted PHP's maintainers to stop building PHP. Other runtimes were built by their communities, he wrote, and companies with the resources should be doing that work. Brian hasn't replied yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132917" rel="noopener noreferrer"&gt;Brian Nguyen, "From mono-implementation risk to spec"&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132925" rel="noopener noreferrer"&gt;Larry Garfield, "This is a money problem"&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Follow-ups (03:02)
&lt;/h2&gt;

&lt;p&gt;If you run PHP on Windows, there's one more update to install. On Monday, Shivam Mathur announced rebuilt Windows packages for PHP 8.2 through 8.5, with Brotli 1.2.1. That fixes a critical out-of-bounds write in the Brotli decoder, rated 9.2, which PHP can reach through the &lt;code&gt;curl&lt;/code&gt; extension when automatic response decompression is on. It's off by default in &lt;code&gt;curl&lt;/code&gt;, but HTTP client libraries can turn it on. The PHP versions don't change, and the dash-1 marks the rebuilt package.&lt;/p&gt;

&lt;p&gt;And on Friday, php.net posted an informational advisory: "We suggest you set session.upload_progress.enabled=0 until the next regular bugfix release, to fully protect from an unlikely RCE vector." It needs an unusual combination of configuration and application code, so the full advisory, for a new CVE, comes with the next release. If you applied that setting as a mitigation last week, keep it in place.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.php.net/archive/2026.php#2026-10-26-1" rel="noopener noreferrer"&gt;Updated PHP Windows builds for the Brotli fix&lt;/a&gt; · &lt;a href="https://www.php.net/archive/2026.php#2026-10-23-1" rel="noopener noreferrer"&gt;Informational advisory: session upload progress&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Newcomer PRs (04:07)
&lt;/h2&gt;

&lt;p&gt;About half of the pull requests from first-time contributors to &lt;code&gt;php-src&lt;/code&gt; have been accepted, and the first success matters most. Artem Ukrainskiy went through a year of data: 831 pull requests from 219 people who opened their first one in that time. 418 were accepted, 157 closed without a merge, and the rest have no outcome yet. A first PR was accepted 29% of the time, and after a first acceptance, 66%. PRs with AI-written descriptions were accepted around 20% of the time, against 55%.&lt;/p&gt;

&lt;p&gt;And speed matters. When a maintainer responds within a day, the median PR closes in about 20 hours. When the first response takes over a week, it's about 32 days. So he asked whether a bot is worth prototyping, one that checks the mechanical things as soon as a PR opens: missing tests, an empty description, the wrong target branch, an obvious duplicate.&lt;/p&gt;

&lt;p&gt;Sjoerd Langkemper replied that his biggest friction as a newish contributor was opening a pull request and having nobody respond. Artem's question started from a new rule by Weilin Du, merged Saturday, that asks contributors, and AI agents, to review an existing fix instead of opening a duplicate. No maintainer has answered the bot question yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://artukrainskiy.github.io/posts/newcomer-prs-in-php-src/" rel="noopener noreferrer"&gt;Artem Ukrainskiy, "What happens to newcomers' PRs in php-src"&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scope RFC (05:30)
&lt;/h2&gt;

&lt;p&gt;PHP has no object that represents a request, because until now a request has been one run of the engine, from startup to shutdown. That breaks down when one process serves many requests at once, and Frode Børli's Scope RFC gives each unit of work an identity: an HTTP request, a queue job, a CLI command. Code anywhere in that request can ask which scope it's in, and keep its own state, like a database connection, keyed by it.&lt;/p&gt;

&lt;p&gt;Fibers and generators belong to the scope they were created in. The primary vote adds only that identity. Two secondary votes would make the superglobals and the session, and then the default locale and timezone, follow the scope. Code that never creates a scope behaves exactly as today, and there's already an extension and a polyfill.&lt;/p&gt;

&lt;p&gt;Larry Garfield called it promising and tightly focused, but asked what it looks like with real dependency injection, rather than a service locator. He also called new scopes with empty superglobals a footgun for legacy code that reads &lt;code&gt;$_POST&lt;/code&gt;. Frode replied that the server fills them when it creates the request scope, the same place that fills them today, and that he'll swap the examples for a container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/scope" rel="noopener noreferrer"&gt;RFC: Scope&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Effect Declarations (06:46)
&lt;/h2&gt;

&lt;p&gt;What if a function had to declare that it starts processes, reads files or makes network requests? Arsan Gamal proposed effect declarations, written after the return type, with optional parameters that narrow them, like the one command this function may run. A separate runtime mechanism would decide what's actually allowed. He named PHP2Shell, the finders' name for last week's vulnerabilities, as the motivation, and compared it to app permissions on a phone. He wrote: "My intention is not to promote process execution, but to make potentially dangerous operations explicit and controllable."&lt;/p&gt;

&lt;p&gt;David Maye liked it, noted that a use-after-free couldn't be contained this way, and suggested prototyping it as an extension with attributes. Damian Jóźwiak asked the same thing: why new syntax instead of attributes? Larry Garfield replied that attributes work for static analysis, but for the engine to enforce it, backward compatibility is the problem. He wrote: "A new PHP release that fails on any function that has a print or fopen statement in it until you add new syntax not available in earlier versions is a complete non-starter." So his first question is how to make it piecemeal opt-in. Calvin Buckley added that these aren't algebraic effects, and suggested a name other than effects or capabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132922" rel="noopener noreferrer"&gt;Arsan Gamal's proposal&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Array Partition (08:12)
&lt;/h2&gt;

&lt;p&gt;Splitting an array into the items that pass a check and the ones that don't takes two passes today, one of them negated. Ayoub Ezzini's RFC adds &lt;code&gt;array_partition&lt;/code&gt;, which returns both halves in one pass, matching first, with keys preserved, so you can destructure straight into two variables.&lt;/p&gt;

&lt;p&gt;mickmackusa asked for any number of groups, keyed by the callback's result, and Morgan for a result keyed &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;. Ayoub kept it to two. Partition means a two-way split in Ruby, Kotlin, Rust, Haskell and Laravel, he wrote, and PHP casts boolean array keys to 1 and 0, so a true-and-false result would quietly swap your variables.&lt;/p&gt;

&lt;p&gt;Tim Düsterhus said a co-worker hand-wrote his own &lt;code&gt;array_partition&lt;/code&gt; just last week, and wrote: "It's a well-written, well-researched and well-argued RFC and I'm in favor of the proposal." Writing the polyfill Tim asked for turned up the open question: whether &lt;code&gt;array_partition&lt;/code&gt; keeps references, like &lt;code&gt;array_filter&lt;/code&gt;, or drops them, like &lt;code&gt;array_find&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/array_partition" rel="noopener noreferrer"&gt;RFC: array_partition()&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Votes (09:22)
&lt;/h2&gt;

&lt;p&gt;Two votes are open, heading in opposite directions. Sjoerd Langkemper's RFC to make &lt;code&gt;hexdec&lt;/code&gt;, &lt;code&gt;octdec&lt;/code&gt;, &lt;code&gt;bindec&lt;/code&gt; and &lt;code&gt;base_convert&lt;/code&gt; throw on invalid characters is at 25 to 1, and it closes November 1st. Muhammed Arshid's &lt;code&gt;Filter&lt;/code&gt; enums RFC is at 2 to 11, with 1 abstention, and it closes November 4th.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/throw_error_for_invalid_characters_for_number_base" rel="noopener noreferrer"&gt;Throw exception for invalid characters in number base functions&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/invalid_filter_options" rel="noopener noreferrer"&gt;Add Filter\Filter and Filter\Flag Enums&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Hits (09:44)
&lt;/h2&gt;

&lt;p&gt;Quick hits. Sjoerd Langkemper reviewed Pratik Bhujel's &lt;code&gt;Io\Terminal&lt;/code&gt; RFC and found two bugs. Pratik pushed fixes within a day, plus one he found himself, and the vote stays on hold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/io_terminal" rel="noopener noreferrer"&gt;Io\Terminal RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Damian Jóźwiak planned the CSV extension vote for November 2nd. Tim Düsterhus asked him to wait after the security release, and questioned giving CSV its own top-level namespace, so Damian postponed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/csv_extension" rel="noopener noreferrer"&gt;CSV extension RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sjoerd also proposed &lt;code&gt;openssl_get_channel_binding&lt;/code&gt;, which ties a login to the TLS connection it runs over, so mail and database clients can offer the PLUS variants of SCRAM logins. Tim asked why it returns null instead of throwing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/openssl_get_channel_binding" rel="noopener noreferrer"&gt;openssl_get_channel_binding RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On blocking server-side request forgery in &lt;code&gt;curl&lt;/code&gt;, Nicolas Grekas wrote "Yes, please make this happen!", for Symfony's HTTP client, and Levi Morrison asked why it should be curl-only rather than cover streams too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132901" rel="noopener noreferrer"&gt;SSRF protection in curl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Máté Kocsis is keeping the length limit in his query parameters RFC, citing the recent CVEs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/query_params" rel="noopener noreferrer"&gt;Query parameter manipulation RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Abbas proposed &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; keywords on top of Fibers, and Frode Børli replied that PHP should go the way of Go, choosing concurrency at the call site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132907" rel="noopener noreferrer"&gt;async/await on top of Fibers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A developer who validates JSON from AI models asked the pattern matching RFC to keep a missing key different from null.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/pattern-matching" rel="noopener noreferrer"&gt;Pattern matching RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And a proposal to call scalar extension methods without parentheses got a strong minus one from Rowan Tommins, for saving two characters per call.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (11:15)
&lt;/h2&gt;

&lt;p&gt;So that's the week. After last week's critical bugs, a call to freeze PHP until it has a formal spec met pushback, and Larry Garfield called the bug-fix bottleneck a money problem. Windows users have rebuilt packages to install, and php.net suggests one session setting until the next release. A year of data showed how much a newcomer's first pull request depends on a fast reply, Frode Børli's Scope RFC would give every request an identity, and &lt;code&gt;array_partition&lt;/code&gt; arrived with Tim's support. Links below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://thephp.foundation" rel="noopener noreferrer"&gt;The PHP Foundation&lt;/a&gt; funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;a href="https://opencollective.com/phpfoundation" rel="noopener noreferrer"&gt;opencollective.com/phpfoundation&lt;/a&gt; — or try guilting your employer into it.&lt;/p&gt;

&lt;p&gt;If you found this useful, a like or a comment helps more people find it. And if you missed &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-oct-22-2026-ii8"&gt;last week's episode&lt;/a&gt;, where two critical PHP vulnerabilities leaked a day before their fix, that's a good one to watch next. Thanks again to &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;Scalpels.app&lt;/a&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>opensource</category>
    </item>
    <item>
      <title>This Week in PHP Internals | Oct 22, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Fri, 23 Oct 2026 01:42:38 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-oct-22-2026-ii8</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-oct-22-2026-ii8</guid>
      <description>&lt;p&gt;On Tuesday, two numbers started going around online, a pair of CVE IDs for PHP, with the wrong score and the wrong release time attached. Within a day, every supported version of PHP had an emergency release out, a day ahead of schedule, and by the release, government websites in four countries had gone dark on purpose. A bug first glimpsed in 2024, that nobody could prove was exploitable, until a few months ago, somebody did.&lt;/p&gt;

&lt;p&gt;Hello world, it's Thursday, October 22, 2026, and here's what happened This Week in PHP Internals. There was no episode last week. I was in Austin for Longhorn PHP, and it never got recorded, so I'm sorry about that. This one covers both weeks. 18 stories, so let's get into it. &lt;em&gt;But first,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What does your team pay every month to get a PDF signed, or to keep every app's logs somewhere you can search them? Scalpels replaces subscriptions like those with open source apps you host yourself. The catalog is up to 13, and two are new since our last episode: Witness, for e-signatures, and Wake, a central log sink for your Laravel apps. Each app is forked into your GitHub organization and deployed to your own Laravel Cloud account, so your data never leaves your infrastructure. The apps are open source, and resources scale to zero by default. And the platform that manages it all is one lifetime purchase, not another subscription. It launches October 31st, at &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;scalpels.app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Release (01:45)
&lt;/h2&gt;

&lt;p&gt;This week's top story is two critical vulnerabilities in PHP itself, both rated 9.2, that let an attacker run code on your server without ever logging in. PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 fix them, and they shipped Wednesday, a day early. And here's the part that matters before any of the engine detail: this is &lt;strong&gt;not&lt;/strong&gt; theoretical.&lt;/p&gt;

&lt;p&gt;Calif, who found it, says it sent the PHP team a working exploit back in August, and the team confirmed it ran. The GitHub advisory for the first bug says that complete remote code execution "was validated over HTTP against mod_php with default PHP input and memory limits …" Default limits. No login.&lt;/p&gt;

&lt;p&gt;So the only real fix is to update. Distributions got the patches ahead of time, so check your vendor. If you're on 8.1 or older there's no release for you, just source backports for 7.4, 8.0 and 8.1. PHP's own advisory on php.net lists some stopgaps if you genuinely can't patch today, but it's blunt about them: they reduce your exposure, they don't make you safe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.php.net/archive/2026.php#2026-10-21-5" rel="noopener noreferrer"&gt;PHP security advisory&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w" rel="noopener noreferrer"&gt;CVE-2026-109618 advisory&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp" rel="noopener noreferrer"&gt;CVE-2026-109619 advisory&lt;/a&gt; · &lt;a href="https://www.php.net/downloads" rel="noopener noreferrer"&gt;downloads&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Breaks (03:09)
&lt;/h2&gt;

&lt;p&gt;Both bugs live in the parts of PHP that nearly every request runs through: memory management and error handling. The Foundation says that's exactly why they're so dangerous, and why they were so hard to fix.&lt;/p&gt;

&lt;p&gt;When PHP hits its memory limit, it has always stopped the request with a C trick called a long jump: it leaps straight back out to a safe point and abandons every function it was in the middle of. The problem is &lt;em&gt;when&lt;/em&gt; that can fire. In a few spots, PHP has set some request data up but not finished wiring it together, and if the memory runs out right there, the long jump bails out and leaves that half-built data behind. Then cleanup comes along and trusts it. PHP's advisory: request cleanup "may then treat the invalid data as valid."&lt;/p&gt;

&lt;p&gt;Now the second bug. A PHP worker handles one request after another, and some internal state is supposed to be wiped between them. A fatal error at the wrong moment can skip that wipe, leaving a pointer aimed at the request that just finished. That request's memory gets freed, the next request lands on the same worker, and it reads the stale pointer before anything resets it. On 8.5 the clearest example is the backtrace PHP saves for a fatal error, which is on by default; the other is session upload progress, also on by default. The team says that first one is the basis of the confirmed attack on &lt;code&gt;mod_php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://calif.io/php2shell/" rel="noopener noreferrer"&gt;Calif's write-up&lt;/a&gt; · &lt;a href="https://www.wiz.io/blog/php2shell-php-rce" rel="noopener noreferrer"&gt;Wiz Research's write-up&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix (04:46)
&lt;/h2&gt;

&lt;p&gt;The fix is a single commit, pushed to every branch, with a blunt title: "Avoid state corruption via bailout." Arnaud Le Blanc wrote it, with Ilija Tovilo, Jakub Zelenka, Nora Dossche and Nicolas Grekas. And it is enormous — 389 files and around 249 new tests.&lt;/p&gt;

&lt;p&gt;The heart of it is this: PHP stops jumping out of an out-of-memory error. When you cross the normal memory limit now, it doesn't bail mid-operation; it raises a flag, finishes what it's safely doing, and reports the error at the next safe point, so cleanup never sees half-built data. There's a second, higher ceiling as a backstop — a hard limit — and if you somehow blow past &lt;em&gt;that&lt;/em&gt;, PHP exits the process on the spot rather than risk running over bad memory. That hard limit is a new setting, &lt;code&gt;memory_hard_limit_percent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the stale-state bug, the patch resets those worker globals early, before the next request can reach them, and makes session upload progress do its work without waking up any of your objects. And &lt;em&gt;that's&lt;/em&gt; why this touches 389 files. Once an out-of-memory can be handled gracefully instead of jumping out, an allocation is allowed to simply fail and return nothing — so every corner of the engine that allocates memory had to be taught to check for that and back out cleanly. A narrow bug, a codebase-wide fix. That's the shape of a problem that sat unsolved since 2024.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/php/php-src/commit/3584a98bda0f2c0d367255b046798b0d3a221a19" rel="noopener noreferrer"&gt;the fix commit&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132894" rel="noopener noreferrer"&gt;PHP 8.6.0 RC4&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Leak Timeline (06:32)
&lt;/h2&gt;

&lt;p&gt;Here's how it got out. The Foundation says the memory bug first surfaced in that 2024 external audit, but with no known way to exploit it, the fix stalled for months over hard trade-offs. About that delay, the Foundation didn't hedge: "We won't pretend otherwise: the delay was a structural failure, caused by both the security team's decision process and its lack of resources."&lt;/p&gt;

&lt;p&gt;What changed is that in August, the security firm Calif, auditing PHP through OpenAI's "Patch the Planet" program, reported a working remote code execution with that same root cause — and OpenAI reported it independently the same day. Suddenly it wasn't theoretical.&lt;/p&gt;

&lt;p&gt;Then, on Tuesday, the two CVE numbers leaked online, with the wrong release time and a wrong score of 10. The Foundation says no technical details leaked with them, but the PHP project moved the release up a day anyway, and not sooner, because distributions were still packaging the fix. Soon after, Calif accidentally posted a video of its exploit running against a number of targets, then took it down — but copies were already spreading. And on Wednesday morning, six hours before the release, the Foundation says Chainguard broke the embargo and shipped patched images, letting anyone diff the binaries for the fix while everyone else was still waiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://thephp.foundation/blog/2026/10/21/todays-php-security-release-and-how-were-strengthening-php-security/" rel="noopener noreferrer"&gt;the PHP Foundation's account&lt;/a&gt; · &lt;a href="https://www.php.net/archive/2026.php#2026-10-20-1" rel="noopener noreferrer"&gt;the pre-announcement&lt;/a&gt; · &lt;a href="https://openai.com/index/coordinated-disclosure-of-critical-vulnerabilities/" rel="noopener noreferrer"&gt;OpenAI's disclosure post&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sites Go Dark (08:10)
&lt;/h2&gt;

&lt;p&gt;And this is where it stops being an engine story and starts being a news story. As the patch landed, governments took some of their own websites offline rather than serve them unpatched. Finland's state IT centre started pulling public services down. France's Interior Ministry said its prefecture sites were temporarily offline pending the patch. The Dutch national cyber agency took down its own website. And Canada's AI minister, Evan Solomon, said some federal sites went dark as, in his words, a "precautionary measure."&lt;/p&gt;

&lt;p&gt;That's the thread running through this whole story: the exploit is proven, and with the patch out, the fix itself shows where to look.&lt;/p&gt;

&lt;p&gt;Now, the one honest caveat. When Chainguard shipped early, its CEO Dan Lorenc said, "I made the call to get these out early when exploits hit in the wild." Others dispute that there ever were working exploits at release. Nils Adermann, who runs Packagist, replied flatly: "This is false. There were no confirmed exploits. All that was reported … was people probing, trying to exploit." The PHP team says the same — it watched for working exploits after the leak and didn't find any at release, and the US agency CISA says it hadn't seen any either. So: the capability is real and proven, the recipe is now out in the open, and neither the PHP team nor CISA had confirmed a break-in yet. Which is exactly the window the patch is for. Update your PHP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.cnbc.com/2026/10/21/government-websites-go-dark-as-software-flaw-sparks-security-scramble.html" rel="noopener noreferrer"&gt;CNBC&lt;/a&gt; · &lt;a href="https://www.cbc.ca/news/business/canadian-government-sites-down-php-cybersecurity-9.7390368" rel="noopener noreferrer"&gt;CBC&lt;/a&gt; · &lt;a href="https://www.theregister.com/security/2026/10/21/php-devs-publish-critical-bug-fix-as-site-owners-warned-pull-em-offline-if-youre-unpatched/5304519" rel="noopener noreferrer"&gt;The Register&lt;/a&gt; · &lt;a href="https://www.cisa.gov/news-events/alerts/2026/10/21/critical-vulnerabilities-php-require-immediate-patching" rel="noopener noreferrer"&gt;CISA alert&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CSV Extension (09:52)
&lt;/h2&gt;

&lt;p&gt;Now, the week we missed, starting with a CSV extension for PHP core, and a debate over whether PHP needs one. PHP 8.6 deprecates the CSV methods on &lt;code&gt;SplFileObject&lt;/code&gt;, and the RFC that did it said future work would be better served by a dedicated extension. Damian Jóźwiak's new RFC is that extension, built on Gina Peter Banyard's CSV extension: 6 functions and a lazy collection in a &lt;code&gt;Csv&lt;/code&gt; namespace. It follows RFC 4180 by default, with no escape character, no dependence on your locale, and multibyte delimiters. Lynn asked for support for streams that are already open, and Damian plans entry points for them.&lt;/p&gt;

&lt;p&gt;Then Artem Ukrainskiy went through the RFC's list of things it says can't be fixed without breaking compatibility, and argued each one can be, in the functions PHP already has. He says the new branch is in good shape, and now faster than &lt;code&gt;fgetcsv&lt;/code&gt; in his benchmarks. He wrote: "My concern is the long-term maintenance cost of introducing a second parser when the existing one can be improved incrementally."&lt;/p&gt;

&lt;p&gt;Damian agreed the RFC's claim was too broad. He pointed to the new DOM API and the URI extension as precedent for a new API beside an old one. Then he laid out 3 directions: improve the existing functions, keep the dedicated extension, or rework it as an object-oriented API. He still prefers a dedicated API, and asked whether a directional vote would help. The thread has been quiet since, and no vote has been called.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/csv_extension" rel="noopener noreferrer"&gt;CSV extension RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132843" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/24199" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/24207" rel="noopener noreferrer"&gt;Artem's locale fix&lt;/a&gt; · &lt;a href="https://github.com/ArtUkrainskiy/php-src-bench/tree/main/reports/csv-pr-24199" rel="noopener noreferrer"&gt;Artem's benchmarks&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON Comments (11:37)
&lt;/h2&gt;

&lt;p&gt;Your &lt;code&gt;tsconfig.json&lt;/code&gt; and your VS Code settings can have comments in them, and &lt;code&gt;json_decode&lt;/code&gt; won't read them. Otar Chekurishvili's new RFC adds two opt-in flags, one for comments and one for trailing commas. They work in &lt;code&gt;json_decode&lt;/code&gt; and &lt;code&gt;json_validate&lt;/code&gt;, strict JSON stays the default, and each flag gets its own vote.&lt;/p&gt;

&lt;p&gt;Back in September, Tim Düsterhus asked for a single JSONC flag instead. The RFC keeps two, because the JSONC spec is still a draft, and it makes trailing commas optional. It also points out that Chromium's JSON reader uses the same two flag names. Tim replied: "I'm not happy, but the rejected [alternative] is well-argued." He also called the RFC "incredibly well-written", and Larry Garfield wrote: "I am forced to agree with Tim. This is a very tight RFC, and I have no remaining objections to it."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/json_comments_trailing_commas" rel="noopener noreferrer"&gt;JSON comments and trailing commas RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132868" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23336" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bcrypt SHA256 (12:37)
&lt;/h2&gt;

&lt;p&gt;The fix for bcrypt's 72-byte limit, from our last episode, got its first challenge: who vouches for it? Mirco Babin said Passlib, the Python library it's borrowed from, isn't a trusted source for security, and asked where bcrypt-sha256 is specified. He also asked about C# and JavaScript apps sharing the database, and said it goes against OWASP's guidance. OWASP's cheat sheet pre-hashes with a secret pepper kept out of the database, where the RFC keys its HMAC with the salt.&lt;/p&gt;

&lt;p&gt;Sjoerd Langkemper asked for a standardized alternative, noting PBKDF2 is a NIST standard, but generally seen as less secure than bcrypt. Mirco has no plans to write an RFC. Rowan Tommins looked up the attack OWASP guards against, password shucking, which needs the same inner hash for the same user somewhere else. He wrote: "To put it another way, the salt in the proposal's HMAC is essentially doing the same thing as the pepper in the OWASP suggestion - making it sufficiently unlikely that an attacker can find the exact inner hash they need somewhere else." Rowan also noticed the same OWASP page recommends a 72-byte maximum, which is what Sjoerd's first RFC proposed. He wrote: "Even an expert opinion is just an opinion, of course, but it does mean we're going in circles a bit."&lt;/p&gt;

&lt;p&gt;Andrey Andreev, who says he's been working on an alternative for weeks, asked for time before another RFC moves ahead. He hoped to post it soon. Nothing yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/bcrypt_sha256" rel="noopener noreferrer"&gt;PASSWORD_BCRYPT_SHA256 RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132784" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pre-hashing-passwords-with-bcrypt" rel="noopener noreferrer"&gt;OWASP on pre-hashing with bcrypt&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Single Binary (14:14)
&lt;/h2&gt;

&lt;p&gt;If PHP ships as one binary for your scripts and for FPM, which half should be in charge? In the week we missed, the answer flipped, and then drew pushback. As we covered last time, Nicolas Grekas and Jakub Zelenka argued the FPM binary should carry the CLI, the way FrankenPHP does. Matthieu Napoli agreed and rewrote the RFC. Now &lt;code&gt;php-fpm&lt;/code&gt; includes the CLI and runs as the CLI when it's invoked under the name &lt;code&gt;php&lt;/code&gt;, with no build option and no &lt;code&gt;--fpm&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;Tim Düsterhus disagreed. He says a binary that changes behaviour based on its name is hard to discover, and naming a symlink wrong could suddenly start FPM and bind a port. He'd rather have an explicit &lt;code&gt;php --fpm&lt;/code&gt;, the way &lt;code&gt;-S&lt;/code&gt; starts the built-in web server. Marc Henderkes agreed with Tim, and doesn't see FrankenPHP replacing FPM any time soon. He wrote: "There has to remain a way to run php without locking ourselves to Go (and realistically Caddy)." And Levi Morrison floated a third option: a shared &lt;code&gt;libzend.so&lt;/code&gt; engine library, which PHP could build in the past.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/single-binary-cli-fpm" rel="noopener noreferrer"&gt;single binary RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132806" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/24192" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PEAR Sunset (15:36)
&lt;/h2&gt;

&lt;p&gt;Back to this week. PHP has voted to stop endorsing PEAR. Nick S.'s RFC closed Monday at 40 to nothing, with no abstentions. The static archive stays up until the end of 2027, and Sebastian Bergmann, who maintains PHPUnit, pointed out that it keeps serving executable code from php.net until then. He wrote: "This includes go-pear.phar, the file that was replaced with a malicious copy in January 2019."&lt;/p&gt;

&lt;p&gt;He suggested a signed list of SHA-256 hashes for every file in the archive, and pinning the hash of the installer that PHP's build downloads and runs when you configure it with PEAR. Before the cut-off, he'd plan brown-outs, so forgotten automation fails early, before the final shutdown. After it, a tombstone PHAR that explains what happened, instead of a plain 404. PHPUnit did the same before its own PEAR server shut down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/end_pear_endorsement" rel="noopener noreferrer"&gt;End PEAR Project Endorsement RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132884" rel="noopener noreferrer"&gt;result&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132881" rel="noopener noreferrer"&gt;Sebastian Bergmann's suggestions&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Votes (16:35)
&lt;/h2&gt;

&lt;p&gt;Three votes this week, with three very different scores. Weilin Du's &lt;code&gt;IntlRelativeDateTimeFormatter&lt;/code&gt; closed at 25 to nothing, and it's already merged for PHP 8.7. Sjoerd Langkemper's RFC to make &lt;code&gt;hexdec&lt;/code&gt;, &lt;code&gt;octdec&lt;/code&gt;, &lt;code&gt;bindec&lt;/code&gt; and &lt;code&gt;base_convert&lt;/code&gt; throw on invalid characters is at 22 to 1, and it closes November 1st.&lt;/p&gt;

&lt;p&gt;The one no is CHU Zhaowei's, only because the RFC throws a plain &lt;code&gt;Exception&lt;/code&gt;, which you can only catch along with every other exception. He pointed out that the 2019 RFC planned an &lt;code&gt;InvalidArgumentException&lt;/code&gt;. Sjoerd replied that a generic exception can become more specific later, and that &lt;code&gt;InvalidArgumentException&lt;/code&gt; signals a programming error, when bad input here might just be user input.&lt;/p&gt;

&lt;p&gt;And Muhammed Arshid's &lt;code&gt;Filter&lt;/code&gt; enums RFC is at 1 to 10, closing November 4th. Tim, one of the no votes, argued two weeks ago that combining the flags as a bitmask turns them into fancy constants. Muhammed replied that many use cases only need a filter, without any flags. Tim's worry is that adding the enums now would likely block a design based on tagged unions later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/reldateformatter" rel="noopener noreferrer"&gt;IntlRelativeDateTimeFormatter RFC&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23514" rel="noopener noreferrer"&gt;merged&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/throw_error_for_invalid_characters_for_number_base" rel="noopener noreferrer"&gt;number base RFC&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132887" rel="noopener noreferrer"&gt;CHU Zhaowei's no&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/invalid_filter_options" rel="noopener noreferrer"&gt;Filter enums RFC&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/tagged_unions" rel="noopener noreferrer"&gt;tagged unions RFC&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PDO Binary (17:52)
&lt;/h2&gt;

&lt;p&gt;PDO drivers handle binary data inconsistently. Calvin Buckley, one of the 8.4 release managers, has an RFC to make it explicit. It offers two shapes: a new &lt;code&gt;PARAM_BINARY&lt;/code&gt; type, or a binary flag you combine with strings and large objects. Calvin says a user asked him that very morning about an ODBC quirk that needed a &lt;code&gt;bin2hex&lt;/code&gt; workaround.&lt;/p&gt;

&lt;p&gt;Ilia went through the RFC against the actual drivers. &lt;code&gt;PARAM_LOB&lt;/code&gt; with a string is already binary in some of them, so he asked what the new constant adds, driver by driver. He wrote that "Neither representation degrades safely": a driver that doesn't know the new type falls back to text in some places, and to a fatal error in the SQL Server driver. He also called the ODBC case a driver issue that can be fixed without a new constant. Calvin plans a per-driver table, and is open to making &lt;code&gt;PARAM_LOB&lt;/code&gt; consistent instead, if that's what people prefer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/pdo_binary" rel="noopener noreferrer"&gt;PDO binary RFC&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/11674" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132876" rel="noopener noreferrer"&gt;thread&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  SSRF in curl (18:56)
&lt;/h2&gt;

&lt;p&gt;If your app fetches URLs your users give it, someone can point it at your own server or your internal network. That's server-side request forgery, and Sjoerd Langkemper reopened the question of how &lt;code&gt;curl&lt;/code&gt; should let you block it.&lt;/p&gt;

&lt;p&gt;Xavier Leune has two pull requests. One exposes curl's own socket callbacks, which hands a socket to userland, and the other adds a pre-connect hook that only PHP would have. The current plan is narrower: just &lt;code&gt;CURLOPT_OPENSOCKETFUNCTION&lt;/code&gt;, with a callback that gets the address and port and returns a boolean. Xavier said that may be a good idea. He's building it as an extension first, as a polyfill for older PHP versions, and he'll follow whatever API the list agrees on for PHP 8.7.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132871" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/22159" rel="noopener noreferrer"&gt;PR #22159&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23657" rel="noopener noreferrer"&gt;PR #23657&lt;/a&gt; · &lt;a href="https://github.com/xavierleune/curl-hardening" rel="noopener noreferrer"&gt;Xavier Leune's extension&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Hits (19:45)
&lt;/h2&gt;

&lt;p&gt;Quick hits, from both weeks. Máté Kocsis answered Tim Düsterhus's 14-point review of the query parameters RFC. He's open to dropping the length limit, fine with renaming &lt;code&gt;list&lt;/code&gt; to &lt;code&gt;toList&lt;/code&gt;, and prefers &lt;code&gt;parseWhatWgUrlSearchParams&lt;/code&gt;, even if it's somewhat verbose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/query_params" rel="noopener noreferrer"&gt;query parameters RFC&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132874" rel="noopener noreferrer"&gt;Máté's reply&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tim sent 15 more points on Jakub Zelenka's polling additions, agreeing with Ilia that they should be voted on separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/poll_api_additions" rel="noopener noreferrer"&gt;Polling API Additions RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Marc still finds &lt;code&gt;getNanoseconds&lt;/code&gt; on &lt;code&gt;Time\Instant&lt;/code&gt; ambiguous, and suggests &lt;code&gt;getNanoOfSecond&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/time_instant_class" rel="noopener noreferrer"&gt;Time\Instant RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tim backs David Carlier's &lt;code&gt;IntlNumberFormatter&lt;/code&gt;, and would deprecate the old &lt;code&gt;NumberFormatter&lt;/code&gt; later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132820" rel="noopener noreferrer"&gt;IntlNumberFormatter discussion&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/issues/24165" rel="noopener noreferrer"&gt;GH-24165&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Juliette Reinders Folmer is writing up the &lt;code&gt;b&lt;/code&gt; prefix deprecation for the 8.7 bulk deprecations RFC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/deprecations_php_8_7" rel="noopener noreferrer"&gt;8.7 deprecations RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Weilin Du's new RFC lets &lt;code&gt;ini_get_all&lt;/code&gt; accept extension names in any case, the way &lt;code&gt;extension_loaded&lt;/code&gt; already does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/case_insensitive_ini_get_all" rel="noopener noreferrer"&gt;ini_get_all RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Frode Børli wants wiki karma for an RFC called Scope, so superglobals, the timezone and the locale can follow each request in long-running servers like FrankenPHP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://fiber-interop.github.io/rfc-scope.html" rel="noopener noreferrer"&gt;Scope RFC draft&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132880" rel="noopener noreferrer"&gt;karma request&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PHP 8.6's fourth release candidate is out with the security fixes, and RC5 is due November 5th.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://news-web.php.net/php.internals/132894" rel="noopener noreferrer"&gt;RC4 announcement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The security release slowed the list, too. Pratik Bhujel planned to open the &lt;code&gt;Io\Terminal&lt;/code&gt; vote this Friday, and Tim Düsterhus replied: "Large parts of the core team have been busy in the past week(s) due to today's security release. I assume not everyone has been able to catch up with RFCs in that time …" Pratik is holding the vote until things settle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/io_terminal" rel="noopener noreferrer"&gt;Io\Terminal RFC&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132895" rel="noopener noreferrer"&gt;Tim's reply&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (21:31)
&lt;/h2&gt;

&lt;p&gt;So that's two weeks. Two critical vulnerabilities in PHP got an emergency release a day early after their CVE numbers leaked, and some governments took their own sites offline until they could patch. If you haven't updated yet, do it today.&lt;/p&gt;

&lt;p&gt;From the week we missed: a CSV extension for core met a review that says to fix the old functions instead, an RFC to allow comments in JSON was called incredibly well-written, the bcrypt-sha256 RFC was challenged over OWASP's guidance, and the single binary flipped and drew pushback. And this week, PHP voted 40 to nothing to stop endorsing PEAR. Links below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://thephp.foundation" rel="noopener noreferrer"&gt;The PHP Foundation&lt;/a&gt; funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;a href="https://opencollective.com/phpfoundation" rel="noopener noreferrer"&gt;opencollective.com/phpfoundation&lt;/a&gt; — or try guilting your employer into it.&lt;/p&gt;

&lt;p&gt;If you found this useful, a like or a comment helps more people find it. And if you missed &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-oct-8-2026-18d0"&gt;our last episode&lt;/a&gt;, where the fix for bcrypt's 72-byte limit was borrowed from a Python password library, that's a good one to watch next. Thanks again to &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;Scalpels.app&lt;/a&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>security</category>
    </item>
    <item>
      <title>This Week in PHP Internals | Oct 8, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Fri, 09 Oct 2026 01:21:51 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-oct-8-2026-18d0</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-oct-8-2026-18d0</guid>
      <description>&lt;p&gt;PHP's default password hash only reads the first 72 bytes of your password. Last week, a plan to make it refuse anything longer split the list, because it would break working apps. This week, a fix that breaks nothing showed up. And it was borrowed from another language's password library.&lt;/p&gt;

&lt;p&gt;Hello world, it's Thursday, October 8, 2026, and here's what happened This Week in PHP Internals. 13 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;How many little monthly subscriptions is your team paying for right now? A private Composer registry here, a mail trap for staging there, a background remover for images, and it all adds up. That's exactly what Scalpels aims to solve. It's a catalog of open source apps, each one aimed at a single paid service and built to replace it: Crate, Sink, Matte, Hone, and a growing list of experimental ones. Scalpels forks the app you pick into your GitHub organization and deploys it to your own Laravel Cloud account, so your data never leaves your infrastructure. Resources scale to zero by default, so a low-use app could cost you pennies. Take updates when you want them, change whatever you like, because it's MIT. And the platform that installs and manages all of them, across your own projects and your clients', isn't another subscription. It's one lifetime purchase, and the catalog keeps growing. If you run an agency, it's a sales tool too: cut your clients' running costs, and close more of the work you pitch. It officially launches October 31st. Early adopter pricing is live now at &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;scalpels.app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bcrypt SHA256 (01:46)
&lt;/h2&gt;

&lt;p&gt;This week's top story is how to fix bcrypt without breaking a single login. Sjoerd Langkemper's RFC to throw on passwords past 72 bytes drew a lot of pushback over backward compatibility, and he says it isn't worth pursuing further for now. It did have support. Jeff Dafoe found the problem in the older part of a PHP codebase he works on, and they forced password resets, writing: "Looking through the lens of software security in 2026, I cannot think of any situation where this function should silently accept more bytes than it can hash."&lt;/p&gt;

&lt;p&gt;The way out came from Tim Düsterhus, who suggested borrowing &lt;code&gt;bcrypt-sha256&lt;/code&gt; from Passlib, a mature Python password library. So Sjoerd's new RFC adds &lt;code&gt;PASSWORD_BCRYPT_SHA256&lt;/code&gt;. Your password goes through HMAC SHA-256 first, so bcrypt only ever sees a 44-byte key, with no null bytes and no 72-byte cliff. In the RFC's example, a 200-character password verifies, and the same password one character shorter doesn't. It's opt-in, the default doesn't change, and the RFC lists no breaking changes. And the hashes are interchangeable with Passlib's. They are longer, so you may need a wider database column.&lt;/p&gt;

&lt;p&gt;Tim wrote: "I believe this is a much better solution than modifying &lt;code&gt;PASSWORD_BCRYPT&lt;/code&gt; in a way that breaks compatibility." Anton Smirnov loves the proposal, and Tim sees nothing fundamentally wrong with the implementation. Making it the default someday is listed as future scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/bcrypt_sha256" rel="noopener noreferrer"&gt;PASSWORD_BCRYPT_SHA256 RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132784" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/24073" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; · &lt;a href="https://passlib.readthedocs.io/en/stable/lib/passlib.hash.bcrypt_sha256.html" rel="noopener noreferrer"&gt;Passlib's bcrypt_sha256&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/bcrypt_max_password_length" rel="noopener noreferrer"&gt;the earlier RFC, set aside&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Votes (03:27)
&lt;/h2&gt;

&lt;p&gt;For 7 straight episodes, nothing was in voting. Now 2 votes are open. Nick S. missed the date he'd planned for the PEAR vote and opened it on Monday instead. It would archive the PEAR site, stop bundling its installer in 8.7, and point php.net to Composer. As of recording, it's 26 to nothing, and it closes October 19.&lt;/p&gt;

&lt;p&gt;Weilin Du's &lt;code&gt;IntlRelativeDateTimeFormatter&lt;/code&gt; is back too. It turns a number and a unit into phrases like "yesterday" or "in 2 weeks". Its first vote, in September, was closed within the hour at 4 to 1, with Tim Düsterhus voting no. Weilin has since adopted Tim's enum design. This time it's 7 to nothing, Tim included, and it closes October 22.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/end_pear_endorsement" rel="noopener noreferrer"&gt;End PEAR Project Endorsement RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132789" rel="noopener noreferrer"&gt;PEAR vote thread&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/reldateformatter" rel="noopener noreferrer"&gt;IntlRelativeDateTimeFormatter RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132830" rel="noopener noreferrer"&gt;IntlRelativeDateTimeFormatter vote thread&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Time Instant (04:21)
&lt;/h2&gt;

&lt;p&gt;The proposed &lt;code&gt;Time\Instant&lt;/code&gt; class had to answer a simple question this week: what does &lt;code&gt;json_encode&lt;/code&gt; give you? Today it's an empty object, and Ilia, otherwise broadly in favour, called that a trap. Rob Landers, who has spent years on a database that has to deal with relativity, wants it to throw instead. Tim and his co-author Derick Rethans said no to both, because there's no single right format, so you pick one. Tim says the real fix belongs in the JSON extension.&lt;/p&gt;

&lt;p&gt;Marc sent a 15-point review, and the &lt;code&gt;getUnixTimestamp&lt;/code&gt; methods are now &lt;code&gt;toUnixTimestamp&lt;/code&gt;. &lt;code&gt;SystemClock&lt;/code&gt; became a singleton, and when Rob noted &lt;code&gt;DateTimeInterface&lt;/code&gt; had no &lt;code&gt;toInstant&lt;/code&gt;, Tim replied: "No. I just forgot that the interface exists. Now added."&lt;/p&gt;

&lt;p&gt;Mirco Babin still wants &lt;code&gt;now()&lt;/code&gt; renamed so one class can also implement PSR-20, and agreed to disagree. Larry Garfield, a long-time member of the PHP-FIG Core Committee, wrote: "This proposal seems like a good step to replacing PSR-20 with something even more standardized and universally available."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/time_instant_class" rel="noopener noreferrer"&gt;Time\Instant and Time\Clock RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132588" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://www.php-fig.org/psr/psr-20/" rel="noopener noreferrer"&gt;PSR-20 Clock&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Io Terminal (05:33)
&lt;/h2&gt;

&lt;p&gt;PHP's proposed terminal API has dropped the interfaces it gained last week. Tim Düsterhus very strongly disagreed with them, with 5 arguments, and the point that the real input and output boundary is the stream, not the terminal. Bob Weinand agreed.&lt;/p&gt;

&lt;p&gt;Larry Garfield said he isn't attached to interfaces, only to an obvious way to test code that reads from the terminal. So Larry sketched a test with in-memory streams, and Tim compiled the branch and confirmed it works for reading lines. Ilia suggested key and secret reads accept ordinary streams too, which he said would close the testing gap on Windows.&lt;/p&gt;

&lt;p&gt;Pratik Bhujel's version 0.4 does all of that. &lt;code&gt;Terminal&lt;/code&gt; is a final class with no interface, scripted streams work for keys and secrets, a forked child no longer resets its parent's terminal, and there are new keys for Insert and Shift-Tab. Pratik wants to move toward a vote once people have reviewed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/io_terminal" rel="noopener noreferrer"&gt;Io\Terminal RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132663" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23941" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Single Binary (06:35)
&lt;/h2&gt;

&lt;p&gt;If you run PHP behind FPM, you probably ship the same engine twice, once in &lt;code&gt;php&lt;/code&gt; and once in &lt;code&gt;php-fpm&lt;/code&gt;. Matthieu Napoli's new RFC adds a build option that puts FPM inside the &lt;code&gt;php&lt;/code&gt; binary, run with a &lt;code&gt;--fpm&lt;/code&gt; flag or through a symlink. He measured it with Bref, on AWS Lambda. The package is 18% smaller zipped, and a minimal FPM app cold-starts 70 milliseconds faster, a 25% cut, because the engine isn't loaded twice.&lt;/p&gt;

&lt;p&gt;Tim sees basically no drawbacks, and asked why anyone should keep a standalone FPM binary at all. Ayesh Karunaratne flagged that &lt;code&gt;-F&lt;/code&gt; means different things to the CLI and to FPM. Larry asked whether this privileges FPM just as FrankenPHP and Swoole are taking off, writing: "I just want to make sure we don't inadvertently lock in FPM as The Way PHP Runs just at the time that it no longer is." Nicolas Grekas says it should be the other way around, with the FPM binary embedding the CLI, the way FrankenPHP does. Jakub Zelenka agreed that makes more sense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/single-binary-cli-fpm" rel="noopener noreferrer"&gt;single binary for CLI and FPM RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132806" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23558" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; · &lt;a href="https://bref.sh" rel="noopener noreferrer"&gt;Bref&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  IO Hooks (07:54)
&lt;/h2&gt;

&lt;p&gt;Ilia's worry about making blocking PHP concurrent is C code written assuming no PHP runs while it waits. He ran Jakub Zelenka's IO Hooks branch and found crashes, like one Fiber freeing a DOM document while another is still saving it. He'd flip the default, so hooked calls stay blocking unless the call site declares itself safe to suspend. Jakub says the branch is a proof of concept, and these are fixable, not a design issue.&lt;/p&gt;

&lt;p&gt;Larry and Sebastian Bergmann asked for the big picture, so Jakub linked a full design doc for all 3 RFCs. Sebastian is looking forward to orchestrating child processes from PHPUnit with it. And Edmond Dantes, whose concurrency RFC proposes a pluggable scheduler, has started testing against it, writing: "Just a couple of weeks ago, I had no hope that async could make it into the language core. But now we have both halves: Scheduler + IO Hooks."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/io_hooks" rel="noopener noreferrer"&gt;IO Hooks RFC&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/poll_api_additions" rel="noopener noreferrer"&gt;Polling API Additions RFC&lt;/a&gt; · &lt;a href="https://gist.github.com/bukka/87359261a4bfaa572ce43c93c0554b55" rel="noopener noreferrer"&gt;design doc for all three RFCs&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23997" rel="noopener noreferrer"&gt;proof of concept&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/async_scheduler_abi" rel="noopener noreferrer"&gt;Concurrency Support in the PHP Engine (scheduler) RFC&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Delegation (08:56)
&lt;/h2&gt;

&lt;p&gt;Karoly Negyesi's &lt;code&gt;implements … by&lt;/code&gt;, which hands an interface's methods to a property, picked up a strong supporter and a familiar problem. Larry Garfield is strongly in favour, after Drupal query classes each carried about 100 lines of pass-through code. James Gilliland agreed, pointing to Laravel's &lt;code&gt;ForwardsCalls&lt;/code&gt; trait.&lt;/p&gt;

&lt;p&gt;Sebastian Bergmann objected that a method added to the interface later gets silently forwarded by every class using it. And fluent methods return the inner object, not yours, which Larry would handle with a mask keyword.&lt;/p&gt;

&lt;p&gt;Rowan Tommins has been here before, writing: "This is where I've always stumbled when trying to come up with similar feature proposals - when you start looking for use cases, a lot of them need just one small thing on top of the forwarded call. So you add an extra keyword here, and a special logic there, and eventually it no longer feels like an elegant shorthand at all."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/php/php-src/pull/24030" rel="noopener noreferrer"&gt;pre-RFC + implementation&lt;/a&gt; · &lt;a href="https://externals.io/message/132737" rel="noopener noreferrer"&gt;thread&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Hits (09:58)
&lt;/h2&gt;

&lt;p&gt;Quick hits. Weilin Du is taking his array shorthand back to the colon, since the parser can tell it apart from a ternary, and he's in no hurry to vote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/array_shorthand" rel="noopener noreferrer"&gt;array shorthand RFC&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/24034" rel="noopener noreferrer"&gt;draft PR&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Juliette Reinders Folmer said she wouldn't pursue deprecating the &lt;code&gt;b&lt;/code&gt; string prefix without more interest, so Daniel Scherzer offered to write the C code and added it to the 8.7 deprecations RFC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/deprecations_php_8_7#deprecate_the_b_prefix_for_binary_strings" rel="noopener noreferrer"&gt;8.7 deprecations RFC: the b prefix&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Muhammed Arshid turned his filter RFC into backed enums for the filter extension's filters and flags. Derick Rethans says removing the extension's default input filtering crippled it, and wants that deprecation undone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/invalid_filter_options" rel="noopener noreferrer"&gt;Filter\Filter and Filter\Flag enums RFC&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/24111" rel="noopener noreferrer"&gt;PR&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Máté Kocsis is back on his query parameters RFC and wants a vote as soon as possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/query_params" rel="noopener noreferrer"&gt;query parameter manipulation RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;David Carlier wants unit formatting in &lt;code&gt;intl&lt;/code&gt;, like 5 kilometers per hour, through a new formatter built from an ICU skeleton.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132820" rel="noopener noreferrer"&gt;intl unit formatting discussion&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/issues/24165" rel="noopener noreferrer"&gt;GH-24165&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And PHP 8.6's third release candidate is scheduled for today, with general availability on November 19.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/todo/php86" rel="noopener noreferrer"&gt;PHP 8.6 release schedule&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (11:01)
&lt;/h2&gt;

&lt;p&gt;So that's the week. Instead of breaking bcrypt, a new RFC proposes an opt-in hash borrowed from Python's Passlib. Two votes are open, and neither has a single no vote so far. &lt;code&gt;Time\Instant&lt;/code&gt; won't pick a JSON format for you, &lt;code&gt;Io\Terminal&lt;/code&gt; dropped its interfaces, and a new RFC would put FPM and the CLI in one binary. IO Hooks got a safety review, and delegation met its edge cases. Links below.&lt;/p&gt;

&lt;p&gt;The PHP Foundation funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;a href="https://opencollective.com/phpfoundation" rel="noopener noreferrer"&gt;opencollective.com/phpfoundation&lt;/a&gt; — or try guilting your employer into it.&lt;/p&gt;

&lt;p&gt;If you found this useful, a like or a comment helps more people find it. And if you missed &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-oct-1-2026-1f24"&gt;last week's episode&lt;/a&gt; — where we found out PHP throws away every byte of your password past the 72nd — that's a good one to watch next. Thanks again to &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;Scalpels.app&lt;/a&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io" rel="noopener noreferrer"&gt;raw feed&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc" rel="noopener noreferrer"&gt;RFC wiki&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week in PHP Internals | Oct 1, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Fri, 02 Oct 2026 00:27:01 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-oct-1-2026-1f24</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-oct-1-2026-1f24</guid>
      <description>&lt;p&gt;Pick a password longer than 72 bytes for a PHP app on the default hash. PHP keeps the first 72 and throws the rest away, without a word. Then it lets you log in with only part of it. This week someone proposed that PHP refuse instead, and the list can't agree it's worth the break.&lt;/p&gt;

&lt;p&gt;Hello world, it's Thursday, October 1, 2026, and here's what happened This Week in PHP Internals. 14 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I think we can all agree that the number of small, paid subscription services we're all being bombarded with is getting a little bit out of hand. And this is what Scalpels aims to solve. It's a collection of professionally built, open source alternatives to the parts you actually use of things like Private Packagist, Mailtrap and remove.bg. You fork them into your own GitHub organization and deploy them to your own Laravel Cloud account, so you're only paying for your own usage, it scales to zero when it's not being used, and you're not just feeding another company's profits. If you want updates, you just pull them down from upstream. And since it's your own fork, you have complete control over the code and the features. And it's all MIT. Find your next tool at &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;scalpels.app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bcrypt Limit (01:19)
&lt;/h2&gt;

&lt;p&gt;This week's top story is a password that's too long. Sjoerd Langkemper's new RFC targets &lt;code&gt;password_hash&lt;/code&gt; with bcrypt, which silently drops everything past the 72nd byte. He'd make that a deprecation in 8.7 and a &lt;code&gt;ValueError&lt;/code&gt; in 8.8. His case is FreshRSS, where a 64-character nonce went in front of the hash, so the 72 bytes held no password at all.&lt;/p&gt;

&lt;p&gt;Kamil Tekiela replied that checking the length is the application's job, not the algorithm's, and Tim Düsterhus agreed in full. It's also 72 bytes, not characters, Tim noted, so non-ASCII passwords could hit it. Rowan Tommins answered: "If every PHP login implementation was reviewed by an expert senior developer, we would not need the password_* API in the first place. The value of this API is that it makes doing the right thing easy, so that you don't need to be an expert in the underlying algorithms to use it safely."&lt;/p&gt;

&lt;p&gt;Robert Chapin showed a shortened password verifying against the full one's hash, and asked: "Is the function named password_verify going to verify the password or not?" Tim says the lost bytes are not where the risk is, and he wrote: "I don't necessarily disagree with the BCrypt truncation being a problem, but in this case the cure is worse than the disease." Derick Rethans is a minus 1, writing: "The problem for me is that this a scary BC break." Overnight, Sjoerd asked Derick what would win him over, &lt;em&gt;maybe switching the default away from bcrypt first&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/bcrypt_max_password_length" rel="noopener noreferrer"&gt;bcrypt max password length RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132689" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23076" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; · &lt;a href="https://pentesterlab.com/blog/freshrss-bcrypt-truncation-auth-bypass" rel="noopener noreferrer"&gt;FreshRSS bcrypt truncation write-up (CVE-2025-68402)&lt;/a&gt; · &lt;a href="https://www.php.net/manual/en/function.password-hash.php" rel="noopener noreferrer"&gt;password_hash() manual&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Regex Object (03:00)
&lt;/h2&gt;

&lt;p&gt;PHP's proposed regex object has broad support and one unpopular word in its name. Gina P. Banyard's &lt;code&gt;CompiledRegex&lt;/code&gt; prototype drew 18 replies, and Sjoerd Langkemper was in favour of "improving the API, instead of slapping more flags onto the existing one." Larry Garfield wrote: "I would ask that we just call it Regex, not CompiledRegex." Casper Langemeijer, Jordi Kroon and Juris Evertovskis also want it to lose the &lt;em&gt;Compiled&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Then there are the 8 boolean flags. Juris says named arguments already make them readable, Gina would rather pass an enum set, which PHP doesn't have yet, and Ayesh Karunaratne and Jordi Boggiano want a factory that takes the modifier letters you already know.&lt;/p&gt;

&lt;p&gt;Osama Aldemeery, who wrote the regex exceptions RFC, pointed out what a compiled pattern can't catch, writing: "Compilation errors are only half of the error story...the other half happens at match time, on patterns that compiled just fine." Tim Düsterhus suggested passing the class could simply switch on throw-on-error, and Osama says he may park his RFC until Gina's reaches a vote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132609" rel="noopener noreferrer"&gt;pre-RFC thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23868" rel="noopener noreferrer"&gt;prototype&lt;/a&gt; · &lt;a href="https://externals.io/message/132426" rel="noopener noreferrer"&gt;PREG_THROW_ON_ERROR thread&lt;/a&gt; · &lt;a href="https://github.com/composer/pcre" rel="noopener noreferrer"&gt;composer/pcre, cited by Jordi Boggiano&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Io Terminal (04:16)
&lt;/h2&gt;

&lt;p&gt;PHP may finally read single key presses without shelling out to &lt;code&gt;stty&lt;/code&gt;. Pratik Bhujel's terminal extension is now the &lt;code&gt;Io\Terminal&lt;/code&gt; RFC for 8.7, covering terminal size, raw mode that restores itself, single keys and hidden input.&lt;/p&gt;

&lt;p&gt;A Symfony Console pull request, approved by Nicolas Grekas, already uses the extension when it's installed, and Nicolas wrote: "PHP definitely needs native terminal support, calling stty is a workaround we've been carrying since way too long." Nicolas suggested raw mode stay on while any token for that terminal is alive and reset when the last one goes, and Pratik adopted it the same day.&lt;/p&gt;

&lt;p&gt;Larry Garfield is in favour, but called false-on-error an anti-pattern and asked for a way to mock it. Version 0.3 makes &lt;code&gt;Terminal&lt;/code&gt; the interface and &lt;code&gt;SystemTerminal&lt;/code&gt; the native class. Pratik is giving it the full 14 days before an intent to vote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/io_terminal" rel="noopener noreferrer"&gt;Io\Terminal RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132663" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23941" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; · &lt;a href="https://github.com/prateekbhujel/php-terminal" rel="noopener noreferrer"&gt;reference extension&lt;/a&gt; · &lt;a href="https://github.com/symfony/symfony/pull/66173" rel="noopener noreferrer"&gt;Symfony Console PR using it&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Time Instant (05:15)
&lt;/h2&gt;

&lt;p&gt;The proposed &lt;code&gt;Time\Instant&lt;/code&gt; class got a bridge back to &lt;code&gt;DateTime&lt;/code&gt; this week. Tim Düsterhus and Derick Rethans added &lt;code&gt;toInstant()&lt;/code&gt; to &lt;code&gt;DateTime&lt;/code&gt; and &lt;code&gt;DateTimeImmutable&lt;/code&gt;, and ISO strings now keep their trailing zeros, to show how precise the value is. They won't write the RFC for testing clocks, because they're not convinced it belongs in core, so Tim wrote: "we want to invite you (as the PHP internals community) to write the follow-up RFC for testing clocks". He also asked for a "LGTM, ship it" if people are happy.&lt;/p&gt;

&lt;p&gt;Mirco Babin answered with 8 comments. One is that &lt;code&gt;Time\Clock&lt;/code&gt; and the PSR-20 clock both define &lt;code&gt;now()&lt;/code&gt;, so one class can't implement both. Tim is keeping &lt;code&gt;now()&lt;/code&gt;, with a 15-year horizon in mind, but he'll discuss a single &lt;code&gt;SystemClock::get()&lt;/code&gt; with Derick. And when Mirco asked for minute precision for bus timetables, Morgan replied: "Well, then it's not an instant, is it?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/time_instant_class" rel="noopener noreferrer"&gt;Time\Instant and Time\Clock RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132588" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://www.php-fig.org/psr/psr-20/" rel="noopener noreferrer"&gt;PSR-20 Clock&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Array Shorthand (06:14)
&lt;/h2&gt;

&lt;p&gt;Weilin Du wants PHP arrays to stop making you type every name twice. His new RFC turns &lt;code&gt;=$x&lt;/code&gt; into &lt;code&gt;'x' =&amp;gt; $x&lt;/code&gt;, in arrays, destructuring and &lt;code&gt;foreach&lt;/code&gt;. It started with a colon and switched to the equals sign within the hour, because the colon clashes with the ternary.&lt;/p&gt;

&lt;p&gt;Sebastian Bergmann will vote against, writing: "A syntax change should be backed by data, for instance an analysis of a representative body of real-world code." David Carlier showed that one missing comma would silently turn one valid program into another. Anton Smirnov pointed out that &lt;code&gt;compact&lt;/code&gt; and &lt;code&gt;extract&lt;/code&gt; still exist.&lt;/p&gt;

&lt;p&gt;On the other side, Christian Schneider has run a local patch for this "for many years". Weilin pointed to the same pattern in Composer, Laravel, PHPUnit and Symfony, but says it already feels like he could withdraw the RFC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/array_shorthand" rel="noopener noreferrer"&gt;array shorthand RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132700" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/24034" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  IO Hooks (07:14)
&lt;/h2&gt;

&lt;p&gt;A new RFC would let ordinary blocking PHP run concurrently, without rewriting it. Jakub Zelenka's IO Hooks starts from the fact that PHP has had Fibers since 8.1, but every blocking function still blocks the whole process, so AMPHP, ReactPHP and Revolt reimplement IO themselves.&lt;/p&gt;

&lt;p&gt;Under his proposal, blocking calls in streams, sockets, curl and the sleep functions get handed to a provider, usually an event loop, which suspends the Fiber until the IO is done. The RFC compares it to Go's runtime. With no provider installed, PHP behaves exactly as today. With one, &lt;code&gt;sleep(1)&lt;/code&gt; in one Fiber is a second of work for the others.&lt;/p&gt;

&lt;p&gt;It depends on a second RFC posted the same evening, Polling API Additions, which fills the gaps in 8.6's Poll API, like sockets, timers and signals. IO Hooks is in an early stage, and neither has replies yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/io_hooks" rel="noopener noreferrer"&gt;IO Hooks RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132727" rel="noopener noreferrer"&gt;IO Hooks thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23997" rel="noopener noreferrer"&gt;proof of concept&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/poll_api_additions" rel="noopener noreferrer"&gt;Polling API Additions RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132725" rel="noopener noreferrer"&gt;Polling API Additions thread&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  List Ban (08:14)
&lt;/h2&gt;

&lt;p&gt;The internals list has removed a contributor. Sepehr Mahmoudi spent the last month posting new-function proposals. On September 15, Derick Rethans warned him over AI-generated content and the number of new threads. On September 21, Ilija Tovilo, as list moderator, set limits of one new thread a month and three emails a week, and called it a last warning. On Sunday Sepehr proposed another RFC, an &lt;code&gt;intl_date_format&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;On Monday Derick confirmed that, after consultation off list, the address is blocked from emailing php.net, wiki access is withdrawn, and it's unsubscribed from the list.&lt;/p&gt;

&lt;p&gt;And this is a tough one. It sucks having to take the nuclear option. He was clearly eager to help, but the list had spent literal weeks trying to get him to slow down, and to stop burdening the list with AI responses, and at some point you've got to enforce the consequences that have been laid out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132664" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://news-web.php.net/php.internals/132684" rel="noopener noreferrer"&gt;Derick Rethans, Sep 28 (news-web)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Hits (09:18)
&lt;/h2&gt;

&lt;p&gt;Quick hits. PHP &lt;code&gt;8.6.0&lt;/code&gt; RC2 is out. RC1 was skipped over a packaging error, so RC2 is the first release candidate, and RC3 is due October 8.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132617" rel="noopener noreferrer"&gt;PHP 8.6.0RC2&lt;/a&gt; · &lt;a href="https://scherzer.dev/Blog/20260923-no-php86-rc-1" rel="noopener noreferrer"&gt;why RC1 was skipped&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same day brought security releases for 8.5, 8.4, 8.3 and 8.2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://www.php.net/releases/8_5_11.php" rel="noopener noreferrer"&gt;PHP 8.5.11&lt;/a&gt; · &lt;a href="https://www.php.net/releases/" rel="noopener noreferrer"&gt;PHP 8.4.26, 8.3.35, 8.2.34&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sjoerd Langkemper changed his number-base RFC to throw a plain &lt;code&gt;Exception&lt;/code&gt; instead of a &lt;code&gt;ValueError&lt;/code&gt;, since bad input isn't necessarily a bug in your program. &lt;code&gt;intval&lt;/code&gt; stays as it is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/throw_error_for_invalid_characters_for_number_base" rel="noopener noreferrer"&gt;number-base functions RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132379" rel="noopener noreferrer"&gt;thread&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Juliette Reinders Folmer wants to deprecate the &lt;code&gt;b&lt;/code&gt; string prefix, a leftover from PHP 6, and Tim suggested adding it to the 8.7 deprecations RFC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132634" rel="noopener noreferrer"&gt;deprecate the b prefix&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/deprecations_php_8_7" rel="noopener noreferrer"&gt;8.7 deprecations RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pedro Veloso floated a &lt;code&gt;#[Pure]&lt;/code&gt; attribute the engine would enforce. Larry Garfield said it needs to do more than the static analysers already do, like memoizing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132643" rel="noopener noreferrer"&gt;pure functions idea&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Karoly Negyesi posted a pre-RFC with an implementation for &lt;code&gt;implements … by&lt;/code&gt;, which hands an interface's methods to a property, modelled on Kotlin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132737" rel="noopener noreferrer"&gt;automated delegation pre-RFC&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/24030" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And Alexander Danilov found that much of post-quantum OpenSSL already works in PHP, and offered small PRs for the gaps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132629" rel="noopener noreferrer"&gt;OpenSSL post-quantum&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the PEAR vote Nick S. planned for September 28 hasn't opened. The RFC is still in discussion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/end_pear_endorsement" rel="noopener noreferrer"&gt;End PEAR Project Endorsement RFC&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (10:36)
&lt;/h2&gt;

&lt;p&gt;So that's the week. An RFC wants bcrypt to refuse passwords past 72 bytes, and the list is split on whether it's worth the break. Several replies want the regex object called just &lt;code&gt;Regex&lt;/code&gt;, &lt;code&gt;Io\Terminal&lt;/code&gt; is an RFC, and &lt;code&gt;Time\Instant&lt;/code&gt; is looking for someone to write testing clocks. The array shorthand met skeptics, and IO Hooks would make blocking code concurrent. The list also removed a contributor after two warnings. Nothing is in voting for a 7th straight week. Links below.&lt;/p&gt;

&lt;p&gt;The PHP Foundation funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;a href="https://opencollective.com/phpfoundation" rel="noopener noreferrer"&gt;opencollective.com/phpfoundation&lt;/a&gt; — or try guilting your employer into it.&lt;/p&gt;

&lt;p&gt;If you found this useful, a like or a comment helps more people find it. And if you missed &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-sept-24-2026-3j03"&gt;last week's episode&lt;/a&gt; — where a new time class couldn't tell you what time it is — that's a good one to watch next. Thanks again to &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;Scalpels.app&lt;/a&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io" rel="noopener noreferrer"&gt;raw feed&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc" rel="noopener noreferrer"&gt;RFC wiki&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week in PHP Internals | Sept 24, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Fri, 25 Sep 2026 02:13:27 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-sept-24-2026-3j03</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-sept-24-2026-3j03</guid>
      <description>&lt;p&gt;PHP is getting a new class for a moment in time. It's precise to the nanosecond. It carries no timezone. It ignores leap seconds on purpose. And it &lt;strong&gt;cannot&lt;/strong&gt; tell you what time it is. Not by itself.&lt;/p&gt;

&lt;p&gt;Hello world, it's Thursday, September 24, 2026, and here's what happened This Week in PHP Internals. 12 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Paying every month for small tools you could own? Scalpels replaces expensive subscriptions with professionally built, expertly maintained apps you host yourself — MIT-licensed, forked into your GitHub organization, on your own Laravel Cloud account. At the early-access price, 500 dollars, once, gets you every app in the catalog, and everything they add later. Find your next tool at &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;scalpels.app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time Instant (00:54)
&lt;/h2&gt;

&lt;p&gt;This week's top story is a time class with no &lt;code&gt;now()&lt;/code&gt; method. On Tuesday Tim Düsterhus and Derick Rethans opened the RFC for &lt;code&gt;Time\Instant&lt;/code&gt; and &lt;code&gt;Time\Clock&lt;/code&gt;, the next piece of the new date and time API that started with &lt;code&gt;Time\Duration&lt;/code&gt; in 8.6. An &lt;code&gt;Instant&lt;/code&gt; is a point on the timeline, with no timezone and nanosecond precision, and it ignores leap seconds by design, because operating systems ignore them too.&lt;/p&gt;

&lt;p&gt;What it doesn't have is &lt;code&gt;Instant::now()&lt;/code&gt;. To find out what time it is, you ask a clock. The RFC adds a &lt;code&gt;Time\Clock&lt;/code&gt; interface with one method, &lt;code&gt;now()&lt;/code&gt;, and a &lt;code&gt;SystemClock&lt;/code&gt; that implements it, which Tim, speaking for himself, says nudges people toward a clock they can inject.&lt;/p&gt;

&lt;p&gt;Seifeddine Gmati wants a static &lt;code&gt;now()&lt;/code&gt; anyway, and would rename the class &lt;code&gt;SystemTime&lt;/code&gt;, as Rust does, saving &lt;code&gt;Instant&lt;/code&gt; for a monotonic clock. Tim's view is that the name follows Java and JavaScript's Temporal, and that a &lt;code&gt;Time\now()&lt;/code&gt; function could come as an immediate follow-up, still in 8.7. Juris Evertovskis added that an &lt;code&gt;Instant&lt;/code&gt; "could be the time of the big bang."&lt;/p&gt;

&lt;p&gt;Larry Garfield is broadly in favour and asked about the serialization format, and Tim replied: "If you need to look at the output of serialization you are doing something very wrong." Larry's bigger ask is a roadmap for the whole new API, writing: "You clearly have a roadmap in your heads. Share it. At whatever level of granularity it exists, share it."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/time_instant_class" rel="noopener noreferrer"&gt;Time\Instant and Time\Clock RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132588" rel="noopener noreferrer"&gt;discussion thread&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc/duration_class" rel="noopener noreferrer"&gt;Time\Duration (PHP 8.6)&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preg Callbacks (02:32)
&lt;/h2&gt;

&lt;p&gt;The regex exceptions RFC's longest-running question has an answer: when your callback throws inside &lt;code&gt;preg_replace_callback&lt;/code&gt;, the exception goes through as-is. Osama Aldemeery, the RFC's author, showed Python, Java and C# all letting it propagate, with Java's docs spelling it out: exceptions are relayed to the caller. He also offered a fallback — if the policy still demanded wrapping, drop the 2 callback functions from the RFC. His scan of the top forty-eight hundred sixty-five packages puts them at 4.9 percent of the calls to the 8 functions.&lt;/p&gt;

&lt;p&gt;Larry Garfield separated implementation details from inputs, writing: "However, I believe Python, C#, and Java are correct in this case: The callback is an input. It's not an implementation detail hidden from the caller, it's explicitly provided by the caller."&lt;/p&gt;

&lt;p&gt;Tim Düsterhus, who wrote the throwables policy, answered on Monday, writing: "I still believe wrapping is the correct choice, but I won't insist on it based on policy." He asked for 2 other changes: errors like a syntax error in the pattern should be a &lt;code&gt;PcreError&lt;/code&gt;, since they aren't meant to be caught, and &lt;code&gt;preg_last_error&lt;/code&gt; should stay untouched.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/preg_throw_on_error" rel="noopener noreferrer"&gt;PREG_THROW_ON_ERROR RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132426" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/22797" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; · &lt;a href="https://github.com/php/policies/blob/main/coding-standards-and-naming.rst#throwables" rel="noopener noreferrer"&gt;throwables policy&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiled Regex (03:49)
&lt;/h2&gt;

&lt;p&gt;A new pre-RFC would let PHP regex patterns drop their delimiters entirely. Gina P. Banyard posted it with a prototype on Wednesday, writing: "I spent the day prototyping an alternative to the PREG_THROW_ON_ERROR RFC as I'm not fully a fan of the approach."&lt;/p&gt;

&lt;p&gt;Her &lt;code&gt;Regex\CompiledRegex&lt;/code&gt; class takes a bare pattern plus named boolean flags — case-sensitive, multi-line, dot-matches-newline and so on — so there's no delimiter, no &lt;code&gt;preg_quote&lt;/code&gt; call, and no modifier letters after the pattern. Patterns must be UTF-8, the &lt;code&gt;D&lt;/code&gt; modifier is always on, and there's a &lt;code&gt;Regex\CompilationError&lt;/code&gt; exception to go with it.&lt;/p&gt;

&lt;p&gt;So far the prototype only plugs into &lt;code&gt;preg_split&lt;/code&gt; and &lt;code&gt;preg_grep&lt;/code&gt;. She says the class could be the base for a proper object-oriented regex API, with &lt;code&gt;match&lt;/code&gt; returning a real bool, but she isn't designing that yet. As of Wednesday night the thread has no replies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132609" rel="noopener noreferrer"&gt;Regex\CompiledRegex pre-RFC thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23868" rel="noopener noreferrer"&gt;prototype&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Main Script (04:51)
&lt;/h2&gt;

&lt;p&gt;A proposal to make PHP files work like runnable Python modules lasted about 24 hours. Tim Düsterhus brought his pull request to the list, &lt;em&gt;at Gina's request&lt;/em&gt;: the CLI would run any closure the main script returns, so one file is a library when included and a command when executed, like Python's &lt;code&gt;if __name__ == '__main__'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Seifeddine Gmati gave it "A BIG yes", then also floated Hack's approach, an &lt;code&gt;#[EntryPoint]&lt;/code&gt; attribute on a function. Rowan Tommins preferred that, since the entry point wouldn't have to sit at the end of the file. Levi Morrison asked why only the CLI, pointed at Symfony's runtime, which already returns a closure from the front controller, and wondered if the status quo is better. Larry Garfield said he'd be minus 1 on the original, because auto-executing a return type "feels hacky".&lt;/p&gt;

&lt;p&gt;On Wednesday Tim dropped it, writing: "Based on the replies it has become clear that the proposed Closure approach has several questions to solve and possibly needs prior design … This requires much more thought than I'm willing to spend right now, given I wanted to solve a specific use case of mine." He'll look at a &lt;code&gt;__MAIN__&lt;/code&gt; constant instead, holding the path of the script that ran first. Alexandru Pătrănescu thinks &lt;code&gt;realpath&lt;/code&gt; on the script filename already does that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132587" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/23658" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Argon2 Default (06:14)
&lt;/h2&gt;

&lt;p&gt;PHP's default password hash, bcrypt, silently truncates at 72 bytes, Andrey Andreev pointed out, and he asked whether it's time to switch &lt;code&gt;PASSWORD_DEFAULT&lt;/code&gt; to Argon2id. His question for the list was narrower than the case for it: Argon2 needs an outside library — libargon2, libsodium, or OpenSSL since 8.4 — so is any dependency a deal-breaker?&lt;/p&gt;

&lt;p&gt;Casper Langemeijer called that as much a pro as a con, since a real crypto library beats rolling your own. Anton Smirnov pointed back to a 2023 thread that called Argon2 weaker than bcrypt at login-speed settings, and Tim Düsterhus said 500 milliseconds is far too long for an interactive login. Andrey measures PHP's Argon2 defaults at about 240 milliseconds, the same as bcrypt at cost 12.&lt;/p&gt;

&lt;p&gt;Jakub Zelenka answered the dependency question: OpenSSL is an external shared library, so it can't be always enabled. Making it a hard requirement would need an RFC of its own, and with OpenSSL 1.1.1 and 3.0 still supported, it would be a long wait anyway. Andrey's last reply, he wrote: "But anyway, if Jakub's comment was describing the status-quo, it's just not happening."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132542" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://externals.io/message/120993#120996" rel="noopener noreferrer"&gt;2023 discussion&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/pull/19360" rel="noopener noreferrer"&gt;enable --with-openssl-argon2 by default&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Str Mask (07:37)
&lt;/h2&gt;

&lt;p&gt;A proposed &lt;code&gt;str_mask&lt;/code&gt; function met the question the list put to &lt;code&gt;array_str_contains&lt;/code&gt;: does this need to be in core? Sepehr Mahmoudi withdrew &lt;code&gt;array_str_contains&lt;/code&gt; on September 17, and the next day proposed &lt;code&gt;str_mask&lt;/code&gt;, which replaces part of a string with a repeated character, for card numbers, phone numbers and tokens.&lt;/p&gt;

&lt;p&gt;Osama Aldemeery replied that it looks identical to &lt;code&gt;substr_replace&lt;/code&gt; with &lt;code&gt;str_repeat&lt;/code&gt;. Pratik Bhujel found it failed open — an out-of-range offset returned the value unmasked — and that a multibyte mask character got cut to a single byte, so Sepehr switched to throwing a &lt;code&gt;ValueError&lt;/code&gt;. Jordi Kroon suggested &lt;code&gt;#[SensitiveParameter]&lt;/code&gt;, and it went in, until Morgan asked "anyone for a game of Hangman?" — not everything masked is sensitive — and it came back out.&lt;/p&gt;

&lt;p&gt;Pratik did find the prior art: Laravel's &lt;code&gt;Str::mask&lt;/code&gt; and CakePHP's &lt;code&gt;Text::mask&lt;/code&gt; do the same core operation, but both handle multibyte text and behave differently at the edges, and he wrote: "evidence that masking exists is different from evidence that this API is the common missing primitive." Casper Langemeijer called it easily done in userland, and Weilin Du showed &lt;code&gt;substr_replace&lt;/code&gt; doing it in one allocation. 30 messages in, no vote is scheduled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/str_mask" rel="noopener noreferrer"&gt;str_mask() RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132539" rel="noopener noreferrer"&gt;thread&lt;/a&gt; · &lt;a href="https://externals.io/message/132488" rel="noopener noreferrer"&gt;array_str_contains withdrawal&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Contributions (09:02)
&lt;/h2&gt;

&lt;p&gt;Running under two of these new-function threads is a question about AI-written contributions. One reply said the mail and proposals read as machine-generated, and the objection, with or without AI, was quality and the time it costs the people reading.&lt;/p&gt;

&lt;p&gt;Pratik Bhujel set out an order of work, writing: "So I think the order should be: demonstrate the use-case, settle the contract, then benchmark the implementation." The author withdrew one RFC and says he's now building and testing everything locally first. Juris Evertovskis replied: "I'm pretty sure most people here will fairly evaluate that work itself, without worrying what has happened previously with other RFCs."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132539" rel="noopener noreferrer"&gt;str_mask thread (order of work)&lt;/a&gt; · &lt;a href="https://externals.io/message/132488" rel="noopener noreferrer"&gt;array_str_contains withdrawal thread&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Hits (09:49)
&lt;/h2&gt;

&lt;p&gt;Quick hits. PHP &lt;code&gt;8.6&lt;/code&gt; is forked. Matteo Beccati cut the branch on Tuesday, the feature freeze is on, master now targets &lt;code&gt;8.7&lt;/code&gt;, and the first release candidate is due today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132585" rel="noopener noreferrer"&gt;PHP 8.6 forked&lt;/a&gt; · &lt;a href="https://github.com/php/php-src/commit/7f8a74fb29d" rel="noopener noreferrer"&gt;branch commit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last week's top story now has a date. Weilin Du updated the &lt;code&gt;IntlRelativeDateTimeFormatter&lt;/code&gt; RFC to use Tim's enums, Tim says it's much better now, and voting should start October 8.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/reldateformatter" rel="noopener noreferrer"&gt;IntlRelativeDateTimeFormatter RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132187" rel="noopener noreferrer"&gt;thread&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And if there are no objections, Nick S. will open the PEAR vote on September 28.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://wiki.php.net/rfc/end_pear_endorsement" rel="noopener noreferrer"&gt;End PEAR Project Endorsement RFC&lt;/a&gt; · &lt;a href="https://externals.io/message/132358" rel="noopener noreferrer"&gt;thread&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pratik Bhujel's &lt;code&gt;php-terminal&lt;/code&gt; extension adds raw mode and single-key reads, so tools like Laravel Prompts can work properly on Windows, and it installs through PIE. Larry pointed out it's 8.7 material now. After Tim's review it lives under an &lt;code&gt;Io\Terminal&lt;/code&gt; namespace with unbacked enums, restores your terminal when its object is destroyed, and is moving to a single object API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://github.com/prateekbhujel/php-terminal" rel="noopener noreferrer"&gt;php-terminal&lt;/a&gt; · &lt;a href="https://externals.io/message/132530" rel="noopener noreferrer"&gt;threads: 1&lt;/a&gt; · &lt;a href="https://externals.io/message/132526" rel="noopener noreferrer"&gt;2&lt;/a&gt; · &lt;a href="https://externals.io/message/132523" rel="noopener noreferrer"&gt;3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And David Maye Kitenge, planning a web framework as a PHP extension, asked about the request lifecycle and threads. Rowan Tommins answered that the CLI leaves parallelism to whoever runs it, and that running user code in a thread per request needs a thread-safe ZTS build, or asynchronous handling in a single thread instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io/message/132534" rel="noopener noreferrer"&gt;extension design Q&amp;amp;A&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (11:08)
&lt;/h2&gt;

&lt;p&gt;So that's the week. PHP's next time class marks a moment and leaves telling the time to a clock, and Larry wants the map for the rest of the new API. The regex RFC's callback question is settled against wrapping, and Gina posted an alternative that compiles the pattern first. A closure-as-entry-point idea lasted a day, the Argon2 default ran into OpenSSL, and &lt;code&gt;str_mask&lt;/code&gt; met the same question as &lt;code&gt;array_str_contains&lt;/code&gt;. And &lt;code&gt;8.6&lt;/code&gt; is frozen, with nothing in voting for a 6th straight week. Links below.&lt;/p&gt;

&lt;p&gt;The PHP Foundation funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;a href="https://opencollective.com/phpfoundation" rel="noopener noreferrer"&gt;opencollective.com/phpfoundation&lt;/a&gt; — or try guilting your employer into it.&lt;/p&gt;

&lt;p&gt;If you found this useful, a like or a comment helps more people find it. And if you missed &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-sept-17-2026-4nch"&gt;last week's episode&lt;/a&gt; — where an RFC was winning its vote 4 to 1 and got closed inside the hour — that's a good one to watch next. Thanks again to &lt;a href="https://scalpels.app" rel="noopener noreferrer"&gt;Scalpels.app&lt;/a&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt; &lt;a href="https://externals.io" rel="noopener noreferrer"&gt;raw feed&lt;/a&gt; · &lt;a href="https://wiki.php.net/rfc" rel="noopener noreferrer"&gt;RFC wiki&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week in PHP Internals | Sept 17, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Fri, 18 Sep 2026 09:14:15 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-sept-17-2026-4nch</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-sept-17-2026-4nch</guid>
      <description>&lt;p&gt;4 yes votes. 1 no vote. On Tuesday morning an RFC went to the ballot, and inside an hour its author closed the poll — while he was &lt;strong&gt;winning&lt;/strong&gt;. Because of what the one no vote &lt;strong&gt;said&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Hello world, it's Thursday, September 17, 2026, and here's what happened This Week in PHP Internals. 10 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Is AI working for your team? Anyone can count the lines it produced. Ballast counts the lines that &lt;strong&gt;survive&lt;/strong&gt;. It reads your git history — never your code — and puts stable velocity next to a durability score between 300 and 850. It's free, and it updates monthly. Get it today at &lt;code&gt;ballast.now&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Corrections (01:00)
&lt;/h2&gt;

&lt;p&gt;1 correction from last week. Around the 6-minute mark I said "Tim Rethans". That's &lt;strong&gt;Derick&lt;/strong&gt; Rethans — who has been Derick for the entire time I've been making this show. Larry Garfield caught it in the YouTube comments, &lt;em&gt;with a smiley face and a good sense of humour.&lt;/em&gt; Thanks, Larry. In my defence, Tim Düsterhus is in every story every week, and apparently my mouth has decided that's just what people are called now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intl Vote (01:27)
&lt;/h2&gt;

&lt;p&gt;This week's top story is a vote that was won 4 to 1 and closed anyway. Weilin Du opened voting on &lt;code&gt;IntlRelativeDateTimeFormatter&lt;/code&gt; on Tuesday morning — ICU's "3 days ago" and "next Sunday" formatting for the &lt;code&gt;intl&lt;/code&gt; extension. Within about 10 minutes Tim Düsterhus had voted no, and the closed poll reads &lt;strong&gt;4&lt;/strong&gt; yes, &lt;strong&gt;1&lt;/strong&gt; no. Tim's reasons were 2-fold. The RFC had changed after his review — Weilin had said the fix was planned, but no mail ever said it was made, so he never re-read it, and the intent to vote had expired. He wrote: "…there was also no email that changes were made to the RFC text (only that some were planned), which is why I didn't recheck the RFC before the vote - and the intent to vote expired." And he doesn't agree with untyped &lt;code&gt;int&lt;/code&gt; constants where enums would do. Weilin called it a misunderstanding, treated it as a major change, and reverted the vote, writing: "There is no need to rush anyways :)" His case for constants is consistency — nothing else in &lt;code&gt;intl&lt;/code&gt; uses enums. On Wednesday Tim sent the discussion thread a middle ground of 3 enums, for style, capitalization and unit, and no namespace, so &lt;code&gt;IntlRelativeDateTimeFormatter::UNIT_DAY&lt;/code&gt; becomes &lt;code&gt;IntlRelativeDateTimeFormatterUnit::Day&lt;/code&gt;. You get IDE autocompletion, documentable cases, and input checks the engine does for free, with &lt;code&gt;RoundingMode&lt;/code&gt; as the precedent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Array Str Contains (03:02)
&lt;/h2&gt;

&lt;p&gt;The benchmark that was supposed to make the case for &lt;code&gt;array_str_contains&lt;/code&gt; came back showing the C function &lt;strong&gt;slower&lt;/strong&gt; than a &lt;code&gt;foreach&lt;/code&gt; loop. Yuya Hamada ran the benchmark test shipped inside the pull request itself: with a match at the start of the array the native call took 578 milliseconds against 14 for userland, it lost in the middle and at the end too, and it only pulled level when nothing matched at all. Sepehr Mahmoudi disputed the run — the files didn't build for him — and on Sunday removed the benchmark tests from the proposal. Kamil Tekiela restated the bar a new standard-library function has to clear, writing: "In recent years, the consensus has been that we only add functions that provide behaviour which is either impossible or very difficult to emulate in userland, or so ubiquitous that it deserves a dedicated function." mickmackusa added that a faster C version is not, by itself, a reason to add anything to the &lt;code&gt;array_&lt;/code&gt; family. Larry Garfield said nobody is reviewing the benchmarks because nobody supports the function, and wrote: "It's OK to have a proposal rejected. Even very experienced long time contributors have ideas declined early on." As of Wednesday night the RFC is still on the wiki, and no vote is scheduled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preg Wrapping (04:19)
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;PREG_THROW_ON_ERROR&lt;/code&gt; RFC now turns mostly on one question: when your own callback throws inside &lt;code&gt;preg_replace_callback&lt;/code&gt;, does PHP wrap it or let it through? Tim Düsterhus, who wrote the throwables policy, wants it wrapped. The 3 others who spoke this week lean the other way. Casper Langemeijer said he isn't aware of any callback in PHP that is wrapped, autoloading included, and Sascha Ploss showed JavaScript and Python letting the callback's exception propagate, and says Java, C#, Rust and Ruby do too. He wrote: "PHP would be an outlier, if it started wrapping them inside PregException." Tim's line is that &lt;code&gt;array_map&lt;/code&gt; exists to run your callback, but with &lt;code&gt;preg_replace_callback&lt;/code&gt;, he wrote, "the high level operation is 'perform a replacement' and the provided callback is just an implementation detail." Osama Aldemeery, the RFC's author, went into the C and corrected himself twice. A callback throw &lt;em&gt;does&lt;/em&gt; set &lt;code&gt;preg_last_error&lt;/code&gt; — to &lt;code&gt;PREG_INTERNAL_ERROR&lt;/code&gt;, because the bail-out path hands the match count to an error function that has no case for it. He wrote: "The engine matched fine, but the "Internal error" is a fallback the bail-out path leaves behind, not a diagnosis of anything PCRE did wrong." And the message-equals-&lt;code&gt;preg_last_error_msg&lt;/code&gt; guarantee only holds for a single flagged call. Tim's Thursday mail adds one more piece: with the flag set, &lt;code&gt;preg_last_error&lt;/code&gt; shouldn't be touched at all, as &lt;code&gt;JSON_THROW_ON_ERROR&lt;/code&gt; already does, and then a single &lt;code&gt;PregException&lt;/code&gt;, or &lt;code&gt;PregError&lt;/code&gt; plus &lt;code&gt;PregException&lt;/code&gt;, is enough. Osama says the policy call is Tim's. Tim hasn't made it yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  PEAR Timeline (06:00)
&lt;/h2&gt;

&lt;p&gt;The PEAR bug data that was thought gone last week has been recovered, and the end-of-endorsement RFC now has a timeline instead of a future-scope section. Nick S. made the edits on Monday: he struck the line saying attempts to reach PEAR's maintainers led nowhere, replaced it with a section on the new situation, and, &lt;em&gt;coordinated with Derick Rethans&lt;/em&gt;, wrote an explicit timeline into the proposal. That is a major change, so discussion stays open until at least September 27. The better news is that Chuck went and recovered the missing bug pages, so the archive can be complete after all — Juliette Reinders Folmer's thanks went to both of them. Jakub Zelenka asked whether php-src should unbundle PEAR &lt;em&gt;before&lt;/em&gt; the site goes static, &lt;em&gt;since he thinks the Windows build still uses the installer&lt;/em&gt;; he plans to resume that pull request in October or November. Nick's answer, &lt;em&gt;checked with Derick&lt;/em&gt;, is that the switch can flip first, as long as &lt;code&gt;go-pear.phar&lt;/code&gt; and the &lt;code&gt;rest&lt;/code&gt; URLs keep serving from the same domain. Either way the vote can't end before mid-October, and Nick doesn't expect anything to land before November. Related, Daniel Scherzer's pull request commits the PEAR installer phar into the repo instead of downloading it when a release is packaged, and targets &lt;code&gt;8.2&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Hits (07:16)
&lt;/h2&gt;

&lt;p&gt;Quick hits. The PHP &lt;code&gt;8.6&lt;/code&gt; branch cut is next Tuesday, September 22, alongside the packaging of &lt;code&gt;8.6.0&lt;/code&gt; RC1 — that's the hard feature freeze, after which master becomes &lt;code&gt;8.7&lt;/code&gt;. Beta 3 shipped last Thursday, RC1 is expected September 24, and &lt;code&gt;8.5.11&lt;/code&gt; and &lt;code&gt;8.4.26&lt;/code&gt; both have release candidates out. Matthieu Napoli got RFC karma for an &lt;code&gt;--enable-cli-fpm&lt;/code&gt; build option that links FPM into the &lt;code&gt;php&lt;/code&gt; binary — &lt;code&gt;php --fpm&lt;/code&gt; runs FPM — because on Lambda, with Bref, a second 24-megabyte binary slows every cold start. Marc Henderkes wants it to be the &lt;em&gt;default&lt;/em&gt;, not an opt-in nobody ships. On the opt-in JSON comments and trailing commas idea from August, Tim suggests a single &lt;code&gt;JSON_ALLOW_JSONC&lt;/code&gt; flag that references the existing standard, which to &lt;em&gt;me&lt;/em&gt; sounds like the correct approach, rather than 2 flags and a combinatorial explosion. Vilius Buividavičius wants &lt;code&gt;MyClass::properties::name&lt;/code&gt; — a &lt;code&gt;::class&lt;/code&gt;-style constant for property names, so Doctrine field references stop being hardcoded strings — and Nick S. pointed him at an earlier thread on the same idea. Alwyn Bester published php-grammar, a source-backed EBNF grammar for PHP &lt;code&gt;8.5&lt;/code&gt; audited against the parser, and is asking the list for review — reviving a 15-year-old thread that asked for an official EBNF for PHP. And David Maye Kitenge, moving an extension from Zephir output to hand-written C, asked whether making a &lt;code&gt;zend_string&lt;/code&gt; &lt;code&gt;static&lt;/code&gt; changes its refcount, and whether interned strings need freeing. Alexandru Pătrănescu answered that &lt;code&gt;static&lt;/code&gt; is about the C variable, not the refcount; interned strings belong to Zend and OPcache, so never free them directly, intern the permanent ones in &lt;code&gt;MINIT&lt;/code&gt;, and don't assume a string interned mid-request outlives the request.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR (09:17)
&lt;/h2&gt;

&lt;p&gt;So that's the week. A vote won 4 to 1 and closed inside the hour, and the enum question it left behind now has a concrete proposal on the table. The &lt;code&gt;array_str_contains&lt;/code&gt; benchmark came back slower than a loop, and the list said, in as many words, that it doesn't want the function. The regex RFC's callback question has 3 people this week against wrapping and the policy's author for it. PEAR's bug data is back, and nothing moves before November. And as of tonight the wiki's list of RFCs in voting is empty, a 5th straight week. Links below. The PHP Foundation funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;code&gt;opencollective.com/phpfoundation&lt;/code&gt; — or try guilting your employer into it. Thanks again to &lt;code&gt;Ballast.now&lt;/code&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week in PHP Internals | Sept 9, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Thu, 10 Sep 2026 04:58:41 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-sept-9-2026-1dao</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-sept-9-2026-1dao</guid>
      <description>&lt;p&gt;A PHP RFC went to a vote on Friday. By Sunday night its author had pulled it back, over a &lt;strong&gt;no&lt;/strong&gt; vote from the person who wrote the policy it broke. What's left is a question every regex you've ever written has an opinion on: when a pattern fails, is that &lt;em&gt;your&lt;/em&gt; bug — or something you &lt;strong&gt;catch&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Hello world, it's Wednesday, September 9, 2026, and here's what happened This Week in PHP Internals.&lt;/p&gt;

&lt;p&gt;11 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt; Is AI working for your team? Lines produced is easy to count. Lines that &lt;strong&gt;survive&lt;/strong&gt; is the number that matters. Ballast reads your git history — never your code — and gives you stable velocity alongside a durability score from 300 to 850. It's &lt;strong&gt;free&lt;/strong&gt;, and it updates monthly. &lt;code&gt;ballast.now&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;3 corrections from last week. PHP &lt;code&gt;8.4.25&lt;/code&gt; was a &lt;strong&gt;bug-fix&lt;/strong&gt; release, not a security release. The announcement mails said security, we repeated it, and Daniel Scherzer pointed us at the NEWS file and the php.net archive. In the libxml-rs story we described 2 contributors without naming them, and Tim Düsterhus pointed out that every &lt;code&gt;From&lt;/code&gt; header in that thread carried a &lt;strong&gt;real name&lt;/strong&gt;. They were James Gilliland and David Carlier. And around the 4-minute mark I said Tim agreed with Sjoerd on the substance. He &lt;strong&gt;disagreed&lt;/strong&gt; — Džuris caught that one on the internals Discord. Thanks to all 3.&lt;/p&gt;

&lt;p&gt;This week's top story is a vote that lasted &lt;strong&gt;56 hours&lt;/strong&gt;. Osama Aldemeery opened voting on &lt;code&gt;PREG_THROW_ON_ERROR&lt;/code&gt; on Friday — an opt-in flag that turns a PCRE error into a &lt;code&gt;PregException&lt;/code&gt;. Within the hour, Tim Düsterhus, who wrote PHP's throwables policy, voted &lt;strong&gt;no&lt;/strong&gt;, writing: "I have just read through the RFC and voted against it, despite being in agreement of the general concept." His 2 reasons: a pattern that fails to compile would keep its warning and the exception would carry only the thin &lt;code&gt;preg_last_error_msg&lt;/code&gt; text, and an exception thrown inside your own &lt;code&gt;preg_replace_callback&lt;/code&gt; callback would pass through &lt;strong&gt;unwrapped&lt;/strong&gt;, where the policy says an extension must wrap what it calls. Osama pushed back, but on Sunday night he pulled the vote, writing: "The flag as it stands violates the throwable policy, as Tim's point shows. That's not something to fix with the vote open, so I'm pulling it back rather than changing the proposal out from under people who already voted." Osama's case against wrapping, in his words: "…wrapping a callback's exception in a PregException produces a PregException that maps to no preg error. You can be holding a PregException while preg_last_error() and preg_last_error_msg() report no error at all." Fixing that means a 3-class hierarchy. Robert Humphries argued that most of those errors — an invalid pattern, bad UTF-8 — are programmer errors, so, arguably, &lt;code&gt;PregError&lt;/code&gt;. Tim agreed compilation failures should be. The RFC is back under discussion; what a regex error &lt;strong&gt;is&lt;/strong&gt; stays open.&lt;/p&gt;

&lt;p&gt;There's a &lt;em&gt;whole class&lt;/em&gt; of engine crashes in PHP that, it's said, &lt;strong&gt;only&lt;/strong&gt; fuzzers and LLMs have ever triggered — and Gina P. Banyard wants PHP to stop fixing them. Her Tuesday mail describes a growing pile of use-after-free reports where an error handler frees the very variable that triggered the warning. Each fix, she says, is a refcount dance around the emit that &lt;strong&gt;everyone&lt;/strong&gt; pays for in performance, and most of the triggers are deprecations PHP 9 removes or promotes to Errors anyway. Her ask is a consensus, ideally without an RFC, that callbacks messing with engine state are &lt;em&gt;undefined behaviour&lt;/em&gt;. The 4 replies from 3 people inside 90 minutes mostly want the bugs fixed. Ilia Alshanetsky says PHP 9 is far off and production migration further, so fix case by case where the cost is low. Ilija Tovilo shares the frustration, but says case by case has already been tried, and wrote: "I'd still very much be in favor of fixing these issues, mainly because they are a big time sink for the security team as well, due to false-positive reports. Arnaud and I were planning on proposing an RFC that mitigates at least a large portion of them…" Tim Düsterhus adds that PHP 9 will bring new deprecations of its own, &lt;em&gt;and we're back where we started.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The PEAR maintainer nobody could reach for &lt;strong&gt;months&lt;/strong&gt; has answered, and according to Nick S. he agrees with the goal. Nick reported Monday that Chuck Burgess of the PEAR Group got in touch and is good with looking at sunsetting the website and removing PEAR from the PHP source. Nick wants to strike the RFC's line about maintainers not responding, and Larry Garfield and Tim Düsterhus both call that a minor change, so the vote can open after a &lt;strong&gt;1-week&lt;/strong&gt; cooldown rather than 2. Rowan Tommins pushed on Nick's word &lt;em&gt;formality&lt;/em&gt;: Chuck is one of 8 listed members of the PEAR Group, so his agreement is one vote, not final authority. He wrote: "I would make a distinction between technical ability and moral authority… Derick has the ability to repoint the DNS for pear.php.net, but holding this discussion and an RFC vote is a way to grant authority." There's a loss, too: the PEAR user accounts are gone, so the missing bug data &lt;strong&gt;can't&lt;/strong&gt; be recovered. Derick Rethans wants the readonly site left up for a year, then a tarball on museum.php.net. And Rowan sent Nick's mirror a pull request with the old site's colours and a &lt;em&gt;locked PEAR&lt;/em&gt; logo. The favicon is under discussion. Derick doesn't care what it is, as long as there is one.&lt;/p&gt;

&lt;p&gt;Last week's top story ended &lt;strong&gt;without&lt;/strong&gt; an RFC — by its author's choice. Luca Rodenhäuser closed the strict-identifiers thread on Thursday, saying the proposal he opened with "did not survive the thread, and I think it was right that it did not." He credited 3 people with changing his mind — Claude Pache for the distinction between a name and an identifier, Rowan Tommins for separating rejecting from normalising, and Larry Garfield for insisting 250 packages wasn't enough, which is how math-php's 888 formula-shaped variables turned up. The question the list never answered is whether non-ASCII identifiers are a supported feature &lt;em&gt;at all&lt;/em&gt;. The manual says they work by accident; fourteen hundred forty-seven of them in the top 5,000 packages say otherwise. His line: "I am not going to write an RFC on a guess." Instead he's sending a documentation PR describing what actually happens today, and leaving one offer on the table — a compiler complaint about invisible characters in names, 68 cases in half a million files, no opt-in needed, &lt;em&gt;if anyone ever wants it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The vote that was due Friday on the number-base functions &lt;strong&gt;didn't open&lt;/strong&gt;. What the list got instead was a naming question. Sjoerd Langkemper's RFC makes &lt;code&gt;octdec&lt;/code&gt;, &lt;code&gt;hexdec&lt;/code&gt;, &lt;code&gt;bindec&lt;/code&gt; and &lt;code&gt;base_convert&lt;/code&gt; throw on invalid input, and after last week's argument that parsing is &lt;em&gt;Exception&lt;/em&gt; territory rather than &lt;em&gt;Error&lt;/em&gt;, he says he's considering it — and asked what the exception should be, with SPL's &lt;code&gt;RangeException&lt;/code&gt; and &lt;code&gt;RuntimeException&lt;/code&gt; on his list. The policy answer, from Rowan Tommins, is that the base has to be &lt;code&gt;Exception&lt;/code&gt; plus something of its own, never SPL — maybe a &lt;code&gt;BaseConversionException&lt;/code&gt;. Tim Düsterhus would go further and throw plain &lt;code&gt;Exception&lt;/code&gt;: these functions sit in &lt;code&gt;standard&lt;/code&gt;, which the policy says not to namespace under, they may be redesigned into an &lt;code&gt;int&lt;/code&gt; or &lt;code&gt;number&lt;/code&gt; namespace later, and promising &lt;strong&gt;nothing&lt;/strong&gt; costs nothing. Morgan asked whether &lt;code&gt;intval&lt;/code&gt; is on the list. No answer yet.&lt;/p&gt;

&lt;p&gt;Whether &lt;strong&gt;speed&lt;/strong&gt; is a reason to put something in PHP's standard library is now a real 2-way disagreement. Last week Tim Düsterhus said performance should not be a factor at all. On Friday Larry Garfield answered that it's one data point among many, writing: "If, to use the current example, benchmarking shows that array_str_contains() is 50% faster in C than in user-space, that's a very different conclusion than if we find it is 0.5% faster." Tim's reply: "Performance is a property of the implementation, not a property of the feature." Something too slow can't ship, but that's a fact about &lt;em&gt;one implementation&lt;/em&gt;; nothing ships &lt;strong&gt;because&lt;/strong&gt; it's fast, and a userland-versus-C benchmark is rarely apples to apples anyway. His alternative is the Optimizer: rewrite &lt;code&gt;array_filter&lt;/code&gt; with a partial application into a &lt;code&gt;foreach&lt;/code&gt; loop, the way &lt;code&gt;8.6&lt;/code&gt; already rewrites &lt;code&gt;array_map&lt;/code&gt;. Larry's position, restated: never decisive, still worth knowing. That's where it sits.&lt;/p&gt;

&lt;p&gt;The scan meant to prove &lt;code&gt;array_str_contains&lt;/code&gt; is a common need found 32 uses in 200 packages — then lost nearly &lt;strong&gt;half&lt;/strong&gt; of them on review. Sepehr Mahmoudi scanned the top 200 Composer packages, about 21,000 files, and counted 32 filter-an-array-by-substring patterns. Rowan Tommins read the results and found at least 15 doing extra logic the function couldn't replace, concluding: "That's still something, but it's not strong evidence that this is an extremely common task." Sepehr agreed the scanner matched shapes rather than closure bodies, and the RFC now says &lt;em&gt;up to&lt;/em&gt; 17 of 32, with a benchmark promised. David Carlier wants the RFC's claim that non-strings are cast proven in the tests. And as of Friday the RFC still wasn't on the wiki's index page — Tim Düsterhus's &lt;strong&gt;second&lt;/strong&gt; reminder.&lt;/p&gt;

&lt;p&gt;Quick hits. Weilin Du intends to open voting on &lt;code&gt;IntlRelativeDateTimeFormatter&lt;/code&gt; on September 15. Tim Düsterhus's one catch is that the RFC clones the ICU number formatter internally, so reconfiguring your &lt;code&gt;NumberFormatter&lt;/code&gt; afterwards would &lt;em&gt;silently&lt;/em&gt; do nothing; Weilin called it a good catch and will refresh it lazily before each format call. Timo Poppinga, new to the list, wants the &lt;code&gt;openssl&lt;/code&gt; extension to expose OpenSSL's provider model &lt;strong&gt;generically&lt;/strong&gt;, so post-quantum algorithms like ML-KEM and ML-DSA work without a constant per algorithm — and says he's probably not the right person to write the C. Ayesh Karunaratne pointed out Sebastian raised the same thing a while back with no traction, and argued the extension should stay as close to OpenSSL as &lt;code&gt;curl&lt;/code&gt; stays to libcurl. Dmytro Kulyk answered Nicolas Grekas's review of the &lt;code&gt;NoSerialize&lt;/code&gt; attribute &lt;strong&gt;10 months&lt;/strong&gt; on, conceding Symfony has no &lt;code&gt;__sleep&lt;/code&gt; the attribute would replace, but Magento 2 has 31 classes of them; the RFC now migrates 107 internal classes and makes &lt;code&gt;unserialize&lt;/code&gt; discard marked properties too. And Florent Morselli, who maintains a base64url library with 46 million downloads, wants the data-encoding RFC's strict mode to actually be &lt;strong&gt;strict&lt;/strong&gt;. Today it skips whitespace and ignores non-canonical trailing bits, which means one WebAuthn credential has 16 spellings, &lt;em&gt;15 of them outside your unique index.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So that's the week. A vote opened on Friday and was gone by Sunday night, and what it left behind is a real argument about whether a regex error is an Exception, an Error, or &lt;strong&gt;both&lt;/strong&gt;. Gina wants a class of engine crashes declared undefined behaviour, and 3 people would rather fix them. The PEAR maintainer answered, the RFC can go to a vote after a 1-week cooldown, and the user accounts are already gone. Last week's top story closed itself with a documentation PR instead of an RFC. And for the &lt;em&gt;fourth&lt;/em&gt; week running, nothing is in the voting phase. Links below. The PHP Foundation funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;code&gt;opencollective.com/phpfoundation&lt;/code&gt; — or try guilting your employer into it. Thanks again to &lt;code&gt;Ballast.now&lt;/code&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week In PHP Internals | Sept 2, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Thu, 03 Sep 2026 01:20:30 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-sept-2-2026-5a9p</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-sept-2-2026-5a9p</guid>
      <description>&lt;p&gt;Hello world, it's Wednesday, September 2, 2026, and here's what happened This Week in PHP Internals.&lt;/p&gt;

&lt;p&gt;11 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt; Is AI working for your team? You can measure the code it produces, but the number that matters is how much of it survives. Ballast reads your git history — never your code — and gives you stable velocity plus a durability score between 300 and 850. Updated monthly, and it's &lt;strong&gt;free&lt;/strong&gt;. &lt;code&gt;ballast.now&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This week's top story starts with a rule most of us never read. Luca Rodenhäuser opened Wednesday with the line in the scanner that defines a PHP identifier — in &lt;strong&gt;bytes&lt;/strong&gt;, not characters. Every byte at or above hex &lt;code&gt;80&lt;/code&gt; is accepted, so &lt;code&gt;$x&lt;/code&gt; followed by a no-break space is a second variable that looks identical. He proposed a per-file &lt;code&gt;declare&lt;/code&gt; to pin that down, then scanned the 250 most-installed Packagist packages and found exactly &lt;strong&gt;one&lt;/strong&gt; identifier that would break.&lt;/p&gt;

&lt;p&gt;Larry Garfield suggested skipping the opt-in and having PHP 9 enforce it, since Symfony fixes its one class and &lt;em&gt;99.99% of developers never notice&lt;/em&gt;. So Luca reran it against the top 5,000 packages. Half a million files turned up fourteen hundred forty-seven non-ASCII identifiers, 91% of them in &lt;code&gt;math-php&lt;/code&gt;, where the variable names spell the formula. He reported the result himself, writing: "So the honest answer to '99.99 % won't notice' is that one library would notice 888 times, and its author chose that style deliberately and has shipped it for years." Then came 3 questions. Derick Rethans asked whether 13.7 kilobytes of tables in every PHP process is worth it. Juliette Reinders Folmer asked what it does to variable variables. And Rowan Tommins asked how much of this is &lt;strong&gt;rejecting&lt;/strong&gt; names and how much &lt;strong&gt;normalising&lt;/strong&gt; them. Each sent him back to measure, and he split his proposal into 3: a diagnostic, a well-formedness rule, and a conformance rule. He says he owes the thread a problem statement.&lt;/p&gt;

&lt;p&gt;Nick Sdot opened an RFC on Thursday to end PHP's endorsement of PEAR. He started about three months ago, going back through every previous discussion and every unvoted attempt, and he's already built a static mirror so the command-line tool keeps working. His case is that PEAR is partly broken, spammed, barely active and now unmaintained. Rowan Tommins backed it. On the argument that PEAR deserves more time to be revived, he wrote: "If that's not long enough, how long is? If the site stays alive in its current state for 10 years, it will continue to be exploited by spammers and probably worse. That's not in anyone's interest." Nick then put a number on the whole thing. &lt;strong&gt;6 packages&lt;/strong&gt; are still publishing to PEAR. 3 of them are PEAR's own infrastructure. 2 more were recently marked unmaintained. Which leaves exactly one independent package still being maintained, and that's &lt;code&gt;Net_SMTP&lt;/code&gt;. Nick gave its maintainer a one-word aside in the thread, and the word was &lt;em&gt;legend&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Sjoerd Langkemper told the list on Friday he intends to open a vote on making the number-base functions throw. His RFC makes &lt;code&gt;octdec&lt;/code&gt;, &lt;code&gt;hexdec&lt;/code&gt;, &lt;code&gt;bindec&lt;/code&gt; and &lt;code&gt;base_convert&lt;/code&gt; throw a &lt;code&gt;ValueError&lt;/code&gt; on invalid input. His framing was that this isn't controversial — the list agreed to it in an earlier &lt;code&gt;base_convert&lt;/code&gt; proposal — and that the RFC is mostly procedure. Tim Düsterhus disagreed on the substance. He argued that passing untrusted input to these functions is an expected use case, which means developers will want to catch what comes back, and drew the line firmly: "The Error hierarchy is not intended to be caught, though. It should thus use something from the Exception hierarchy." Sjoerd asked whether that distinction is written down anywhere. It is. Tim pointed him at the throwables section of the coding standards policy, and quoted it: "The Error hierarchy MUST NOT be used for errors that are expected to be thrown (and caught) during normal operation of a PHP program. … a parsing function that is expected to be used with untrusted input must not throw an Error if the input is malformed." Base conversion, Tim argues, &lt;strong&gt;is&lt;/strong&gt; parsing.&lt;/p&gt;

&lt;p&gt;The array-filtering function we covered last week came back on Sunday, renamed &lt;code&gt;array_str_contains&lt;/code&gt; and retargeted at &lt;code&gt;8.7&lt;/code&gt;. Sepehr Mahmoudi's case is that filtering an array by substring is common enough to deserve C, instead of paying for a closure on every element. Seifeddine Gmati went first and went broad. He couldn't remember ever writing that code, said the same argument would justify &lt;code&gt;array_str_starts_with&lt;/code&gt; and a few hundred more combinations, and pointed out that nothing in the name tells you it filters. He called it redundant. Bruce Weirdan turned the performance claim around, asking whether the closure overhead itself should be fixed, since that would speed up &lt;strong&gt;every&lt;/strong&gt; builtin that takes a callable. Kamil Tekiela asked what the numbers actually are, and said he'd never hit it as a bottleneck. Sepehr then walked back his own strongest claim, agreeing that a filter has to read the whole array rather than stopping at the first match. He's promised static analysis across Packagist to back the frequency claim.&lt;/p&gt;

&lt;p&gt;Last week's top story was the list arguing about machine-written mail in the abstract. This week it stopped being abstract. Juris was the one who did the work, drafting the guideline text he thinks a newcomer should get. It says to write the message yourself rather than rephrase yourself with an LLM, and that there's no requirement to have perfect English on that list — plenty of productive contributors are more fluent in C and PHP than in English. Then he demonstrated it instead of asserting it. He wrote his next 3 paragraphs in Latvian, machine-translated them, and sent both versions in the same message, arguing the imperfect translation stays closer to what he meant than anything a chatbot would phrase for him. Then Sepehr Mahmoudi acknowledged that he had been having AI write his replies. Weilin Du asked the thread to stop naming people, saying it had become a place to point fingers rather than a place for technical debate. Yuya Hamada apologised for going too hard, and it stopped there. &lt;strong&gt;There's still no written policy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Théo Attali introduced himself on Saturday with a first contribution and a small, well-argued gap. PHP's &lt;code&gt;DATE_RFC3339_EXTENDED&lt;/code&gt; gives you milliseconds with a numeric offset, but a lot of systems expect the same instant with a &lt;code&gt;Z&lt;/code&gt; on the end, which is what JavaScript's &lt;code&gt;toISOString&lt;/code&gt; produces. He proposed a constant for it, and flagged the flaw in his own idea before anyone else could. A format string containing a literal &lt;code&gt;Z&lt;/code&gt; can't force the value into UTC. Andreas Heigl agreed, with unusual standing to do it — he added the extended constants. He wouldn't add any more now, since a constant only helps people who've already upgraded, and pointed Théo at a userland formatter built on one line that has worked since PHP 5.3. Théo revised on the spot, proposing an instance method instead. Then Tim Düsterhus redirected it. He pointed out that PHP 8.6 ships the first piece of a new date and time API, and that the proposed &lt;code&gt;Time\Instant&lt;/code&gt; is deliberately timezone-less — which makes a Zulu-format method an obvious thing to add &lt;em&gt;there&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;An offer arrived on Saturday from a name the list hadn't seen before. Riaan de Beer has written &lt;code&gt;libxml-rs&lt;/code&gt;, a native-Rust reimplementation of libxml2 that's compatible at the C ABI level, and he asked whether php-src would be open to a test build against it. He says &lt;code&gt;xmllint&lt;/code&gt; and &lt;code&gt;xmlcatalog&lt;/code&gt; come out byte-identical against libxml2 2.15.3 across eleven hundred ten tests, and he's careful about the ask — an experimental alternative provider, not a default. What the list answered was his opening sentence. He'd said libxml2 has been unmaintained since December 2025, and Pierre replied that the repository has had many commits since, and that a mature XML library not cutting frequent releases isn't an abandoned one. 2 more contributors agreed. One wrote that libxml2 was only briefly unmaintained before new maintainers stepped up, and the other added that one of those maintainers helps php-src out directly. &lt;em&gt;Nobody has answered the actual question yet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The question of whether RFCs should ship a userland polyfill got 2 substantial answers this week. Nicolas Grekas answered from the Symfony side, which is the side that does the work. Every polyfillable feature ends up in the &lt;code&gt;symfony/polyfill&lt;/code&gt; monorepo anyway, and the one that ships is often not the one in the RFC. Polyfills, he concluded, need a separate workflow. Then Tim Düsterhus answered the other argument for them, which was Larry Garfield's suggestion that a polyfill gives you something to benchmark the C against. Tim wrote: "I believe performance should not be a factor in deciding what should be part of the stdlib and what should not: Performance is a moving target and what might be true today might no longer be true tomorrow… Once we add something to the stdlib we need to maintain it for the next 15+ years. (Broad) usefulness and good API design must be the deciding factors…" He added that PIE has made building a private extension easier than it's ever been.&lt;/p&gt;

&lt;p&gt;Quick hits. 3 releases landed in 3 days. Calvin Buckley put out &lt;code&gt;8.4.25&lt;/code&gt;, a &lt;strong&gt;security&lt;/strong&gt; release, so that one's worth doing today. Daniel Scherzer released &lt;code&gt;8.5.10&lt;/code&gt;, a bugfix. And Matteo Beccati has &lt;code&gt;8.6.0beta2&lt;/code&gt; up for testing. Last night Nick Sdot replied to the &lt;code&gt;nameof&lt;/code&gt; RFC to say he'd like to see it in &lt;code&gt;8.7&lt;/code&gt; — and the message he was replying to was posted in May of 2023. &lt;em&gt;3 years and 3 months is a long time to keep a browser tab open.&lt;/em&gt; And on the named parameter lists thread, somebody answered Larry Garfield's question from a fortnight ago about why people treat a small data structure as unworthy of being a class. The answer wasn't performance. It's cognitive cost — returning 2 values as an array and unpacking them at the call site is easier to hold in your head than a dedicated object, and static analysis can describe that array well enough that you don't lose much.&lt;/p&gt;

&lt;p&gt;So that's the week. No RFC has been in the voting phase for 3 weeks running. Somebody scanned half a million PHP files to work out what a PHP identifier is, and came back having split his own proposal into 3. There's an RFC to end PHP's endorsement of PEAR, which has one maintained package left on it. There's a real disagreement about whether base conversion counts as parsing, which decides which kind of throwable it gets. A new array function has 4 people against it and nobody for it. And the argument about who writes the mail on that list got a concrete answer. Links below. The PHP Foundation funds more than half of ongoing &lt;code&gt;php-src&lt;/code&gt; commits, so if you use the language, maybe consider donating at &lt;code&gt;opencollective.com/phpfoundation&lt;/code&gt; — or try guilting your employer into it. Thanks again to &lt;code&gt;Ballast.now&lt;/code&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week In PHP Internals | August 26, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Fri, 28 Aug 2026 04:05:42 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-august-26-2026-2675</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-august-26-2026-2675</guid>
      <description>&lt;p&gt;Hello world, it's Wednesday, August 26, 2026, and here's what happened This Week in PHP Internals.&lt;/p&gt;

&lt;p&gt;10 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt; You shipped a lot of code this quarter, but do you know how much of it is actually still there? Ballast reads your git history — never your code — and scores what survives. Stable velocity, plus a durability rating between 300 and 850 — &lt;em&gt;like a credit score for your codebase&lt;/em&gt; — updated every month, and it's &lt;strong&gt;free&lt;/strong&gt;. &lt;code&gt;ballast.now&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This week's top story isn't really about PHP. It's about how the internals list talks to itself. Messages have been arriving that were clearly written or heavily assisted by a large language model — that flat, over-professional register that thanks you warmly and then restates your own point back at you — and somebody finally said the quiet part in plain text. 24 messages followed, about where the line actually sits. Nobody argued against translation. English is a second or third language for a good part of that list, and that is a real accessibility question rather than a laziness one. What people object to is &lt;strong&gt;authorship&lt;/strong&gt; — the argument itself being handed to a machine — and the harder problem underneath, which is that there's no reliable way to tell the difference from the outside. Nothing's been written down yet. But if you want a say in what does get written down, the community Discord is at &lt;code&gt;phpc.chat&lt;/code&gt;, and there's an internals channel there. &lt;em&gt;It's a community server, not an official PHP one.&lt;/em&gt; There's a thread in it working on exactly these guidelines. So if you want to head there and argue with us about what should be in the guidelines, feel free to join the discussion.&lt;/p&gt;

&lt;p&gt;A new RFC opened on Saturday, from the same contributor whose last one had just been withdrawn. Sepehr Mahmoudi proposed &lt;code&gt;array_match()&lt;/code&gt;, which filters an array down to the values containing a substring, implemented in C so you don't have to pay for a closure on every element. Yuya Hamada replied within the hour, asking whether &lt;code&gt;array_filter()&lt;/code&gt; isn't already enough, pointing at a GitHub search full of userland functions already named &lt;code&gt;array_match&lt;/code&gt; that don't all behave alike, and noting that the &lt;code&gt;str_icontains&lt;/code&gt; RFC was declined, so an ASCII-only case-insensitive flag is a hard sell. Then Tim Düsterhus pointed out that in &lt;code&gt;8.6&lt;/code&gt; this is already 1 line, because partial function application lets you drop &lt;code&gt;str_contains&lt;/code&gt; into &lt;code&gt;array_filter()&lt;/code&gt; with a placeholder. Christian Schneider noted that &lt;code&gt;preg_grep()&lt;/code&gt; has done basically the same job for years.&lt;/p&gt;

&lt;p&gt;The case against it was mostly one case, made 5 ways. Ayesh Karunaratne went after the premise, writing: "I have worked on Drupal, WordPress, Silex, and bespoke code bases, spending enough time profiling them. An array string search has never been a bottleneck." Larry Garfield called it an XY problem and said huge in-memory arrays are a code smell to begin with. mickmackusa offered the alternative nobody else had — make &lt;code&gt;str_contains()&lt;/code&gt; polymorphic, the way &lt;code&gt;str_replace()&lt;/code&gt; already takes an array. Sepehr has since dropped the case-insensitive flag, renamed it &lt;code&gt;array_str_contain()&lt;/code&gt;, and moved the target to &lt;code&gt;8.7&lt;/code&gt;, since &lt;code&gt;8.6&lt;/code&gt; is frozen. &lt;strong&gt;Nobody's argued in favour of it so far.&lt;/strong&gt; &lt;em&gt;The proposal, so far, contains no support.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nick Sdot brought a documentation question to the list on Thursday. He's restructuring PHP's internals book, the docs that live inside &lt;code&gt;php-src&lt;/code&gt;, and his first pull request converts the pages from reStructuredText to Markdown — a light 1,100-line mechanical diff that nets out 86 lines shorter. Ilija Tovilo, who set the book up, called it churn, and answered that the source is neither pure Markdown nor reStructuredText but MyST, so renaming files fixes some rendering and breaks the reStructuredText-flavoured parts. His real objection was the diagnosis. He wrote: "None of this is wrong, but I don't think the docs have stalled because the syntax is too hard. Rather, more time should be designated to them." Weilin Du and Calvin Buckley both said the effort belongs in the content. Nick's clarification explains the thread. The old docs folder he's merging in is &lt;strong&gt;already Markdown&lt;/strong&gt;, so a conversion happens in one direction or the other. It's still open.&lt;/p&gt;

&lt;p&gt;Robert Chapin spent the week working through an old RFC. Deprecate Fuzzy Type Casts, by Alexandre Daubois and Nicolas Grekas, dates to January, is still under discussion, and still targets &lt;code&gt;8.6&lt;/code&gt; on the wiki — which Robert would like changed, given there's been no discussion since. His objection is that the RFC's own migration guidance doesn't hold up. He points out that with the string &lt;code&gt;1.5&lt;/code&gt;, &lt;code&gt;is_numeric()&lt;/code&gt; returns true, so the validate-before-casting example still triggers the deprecation, while &lt;code&gt;is_int()&lt;/code&gt; and &lt;code&gt;is_float()&lt;/code&gt; return false for every numeric string. He says the &lt;code&gt;filter_var()&lt;/code&gt; alternative doesn't guarantee an integer back either. He asked: "Are developers expected to replace a sing[le] type cast with 8 lines of code for PHP 8.6?" &lt;em&gt;Nobody has answered him.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A process question opened yesterday morning. Sepehr Mahmoudi noticed that some RFCs proposing new functions include a userland polyfill and some don't, and asked whether the RFC template should recommend one wherever that's feasible. His reasons are that a polyfill pins down the exact behaviour, edge cases and all, without anyone reading the C, and that it gives teams like Symfony's polyfill maintainers an accurate head start. Larry Garfield called recommended-where-relevant-but-not-required a reasonable policy, and added a second use for it, saying: "And it would also give us a target to benchmark against to see if putting it in C really has a performance benefit." &lt;em&gt;Which is exactly what 2 people spent the weekend asking Sepehr for on his other proposal.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Gina P. Banyard posted a correction on Friday to an already-accepted RFC. Steven Wilton's SNMP improvements proposal states that its target is the next stable release for all currently supported PHP versions. Gina's point is that this runs against the release process policy on patch versions, so the changes will land in &lt;code&gt;8.6&lt;/code&gt; only. She also asked for a design change — the new integer constants in the output-controls section would become PHP &lt;strong&gt;enums&lt;/strong&gt; instead, which improves type safety in userland and translates the C enums SNMP already defines into PHP ones. The plan is to have it merged in time for &lt;code&gt;8.6.0&lt;/code&gt; beta 2.&lt;/p&gt;

&lt;p&gt;Weilin Du, who maintains the &lt;code&gt;intl&lt;/code&gt; extension, spent part of the week handing out work. He'd like some of the extension's constants turned into enums, proper namespaces on its classes so they stop colliding, and the remaining gaps between PHP's APIs and the underlying ICU APIs filled in. He was blunt about the error handling, writing: "the error state stuff in the extension is, frankly, bad, in my opinion, and could be optimized since it has caused a lot of very stupid bugs." He suggested the enums and namespaces could be an &lt;code&gt;8.7&lt;/code&gt; RFC if somebody picks it up. Yuya Hamada added the reason it matters. Feedback from right-to-left language users is thin across the &lt;strong&gt;whole&lt;/strong&gt; industry, not just PHP, and PHP's internationalisation depends on getting it.&lt;/p&gt;

&lt;p&gt;Quick hits. &lt;code&gt;array_search_range()&lt;/code&gt;, last week's top story, is officially withdrawn — mickmackusa posted a 7-point review hours after we recorded, and Sepehr Mahmoudi pulled it on Thursday and called it a valuable learning experience. Weilin Du's extension-name case sensitivity proposal is going to a vote, eventually. A core developer objected, which under policy makes it an RFC, and he'll open that after the &lt;code&gt;8.6&lt;/code&gt; branch is cut on September 22, with both behaviours on the ballot for &lt;code&gt;8.7&lt;/code&gt;. And Zachary DuBois introduced himself on Thursday, asked whether adding missing libsodium functions needs an RFC or just a pull request, was told to open the pull request, and had it up by Sunday. It adds X-Wing and ML-KEM-768 bindings to the &lt;code&gt;sodium&lt;/code&gt; extension. &lt;em&gt;Post-quantum key encapsulation, arriving as somebody's first pull request. Quantum-resistant, and so far review-resistant.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So that's the week: no RFC in the voting phase for the second week running; a long argument about who is actually writing the mail on the internals list; a new &lt;code&gt;array_str_contain()&lt;/code&gt; proposal with 5 people against it and nobody for it; a documentation pull request that turned out to be a consolidation question rather than a format preference; unanswered holes in the fuzzy casts migration path; and post-quantum crypto arriving as somebody's first pull request. Links to every thread are below. The PHP Foundation bankrolls a lot of &lt;code&gt;php-src&lt;/code&gt; development, so if you use the language, maybe consider donating at &lt;code&gt;opencollective.com/phpfoundation&lt;/code&gt; — or try guilting your employer into it. Thanks to &lt;code&gt;Ballast.now&lt;/code&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week In PHP Internals | August 19, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Fri, 21 Aug 2026 22:56:58 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-august-19-2026-6mh</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-august-19-2026-6mh</guid>
      <description>&lt;p&gt;Hello world, it's Wednesday, August 19, 2026, and here's what happened This Week in PHP Internals.&lt;/p&gt;

&lt;p&gt;12 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt; Is AI working for your team? Ballast answers that for &lt;strong&gt;free&lt;/strong&gt;. It reads your git history — never your code — and gives you 2 numbers every month. Stable velocity tells you how much of what you ship survives. A durability score from 300 to 850 tells you whether it holds up. &lt;code&gt;ballast.now&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This week's top story: a 5-argument function proposal turned into 25 messages, 3 threads, and the week's central design argument. Sepehr Mahmoudi, who introduced himself to the list 8 days ago, proposed &lt;code&gt;array_search_range()&lt;/code&gt; — an &lt;code&gt;array_search()&lt;/code&gt; that takes an offset and a length, so you can search part of an array without building an intermediate copy with &lt;code&gt;array_slice()&lt;/code&gt;. Weilin Du replied the same evening to say the soft feature freeze had already closed &lt;code&gt;8.6&lt;/code&gt; to it. Then Rowan Tommins raised the objection that shaped everything after it, suggesting: "I think it would be better to design something more composable - that is, a way to create a 'lazy array slice', and then accept that in functions which can use it safely." He pointed at Swift, which has types that let you refer to part of an array &lt;strong&gt;without copying any of it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rowan put his objection plainly: "if we add an ArraySlice type then array_search_range would immediately become redundant." Sepehr's answer is that the general thing doesn't exist, and that building it would mean a new type in the engine and updates to potentially hundreds of array functions. Larry Garfield sided with Rowan and suggested shelving it. mickmackusa said he'd never had a professional project that required the function, and put a design question back: "If a PHP array needed a pagination-style search function, should perhaps the data structure be reconsidered?" Rowan then broke his own idea into 3 shippable steps. An optimized &lt;code&gt;ArraySliceIterator&lt;/code&gt; comes first, then &lt;code&gt;iter_search&lt;/code&gt; and &lt;code&gt;iter_any&lt;/code&gt; functions that would work with &lt;strong&gt;any&lt;/strong&gt; iterator, and possibly syntax after that. He wrote the first 2 in under 20 lines each, and a polyfill for Sepehr's function on top. Sepehr added a Polyfill section to the RFC, and Rowan pointed out that the version now on the wiki calls &lt;code&gt;array_slice()&lt;/code&gt;, which copies the array. &lt;em&gt;That is the cost the proposal exists to avoid.&lt;/em&gt; As of this recording the RFC is still a draft, still targeting &lt;code&gt;8.6&lt;/code&gt;, and Rowan's GitHub review found the implementation still walking the entire array.&lt;/p&gt;

&lt;p&gt;Something small and irritating went to the list on Saturday. 4 functions take an extension name, and &lt;code&gt;ini_get_all()&lt;/code&gt; is the only one of them that's &lt;strong&gt;case-sensitive&lt;/strong&gt;. Weilin Du opened a pull request to bring it into line with &lt;code&gt;extension_loaded()&lt;/code&gt;, &lt;code&gt;phpversion()&lt;/code&gt; and &lt;code&gt;get_extension_funcs()&lt;/code&gt;. Sjoerd Langkemper agreed it should be consistent, then asked the question that turned the thread around: "Another option to make them consistent would be to have them all case-sensitive. Have you considered that?" &lt;em&gt;He also spotted that the manual's lowercase-only note for &lt;code&gt;get_extension_funcs()&lt;/code&gt; isn't true. AllenJB traced it to a change back in PHP &lt;code&gt;5.0.4&lt;/code&gt;, and there's a docs issue open now.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Daniel Scherzer objected, arguing PHP should make all 4 case-sensitive instead, since BC breaks have an established path through deprecation and removal in the next major version. Weilin agreed and &lt;strong&gt;withdrew his own proposal&lt;/strong&gt;, saying he'd add extension-name case sensitivity to the &lt;code&gt;8.7&lt;/code&gt; deprecations RFC instead. And then 3 people showed up to argue for the thing he'd just withdrawn. Aleksander Machniak listed &lt;code&gt;PDO&lt;/code&gt;, &lt;code&gt;SimpleXML&lt;/code&gt;, &lt;code&gt;Xdebug&lt;/code&gt; and &lt;code&gt;swoole&lt;/code&gt;, and asked why a developer should have to know the exact casing of each one. Matteo Beccati called the alternative "one of those useless BC breaks that make the user experience worse instead of improving it." He also noted that &lt;code&gt;composer.json&lt;/code&gt; generally writes its extension requirements in lowercase. Juliette Reinders Folmer had the last word, with the practical cost. Build a version list with &lt;code&gt;get_loaded_extensions()&lt;/code&gt; and you'd have to lowercase every name before &lt;code&gt;phpversion()&lt;/code&gt; would take it. Nobody has replied to her yet.&lt;/p&gt;

&lt;p&gt;Henrik Skov posted an idea on Tuesday morning. He wants a &lt;code&gt;params&lt;/code&gt; keyword that lets you name a block of arguments once and spread it into a call, so a 6-argument cookie call collapses to 1 line. One of the 6 arguments in his own example is labelled "Can't remember what this is." AllenJB replied 22 minutes later that PHP already does this with named arguments and array unpacking. Henrik came back with the actual requirement. He wants the expressions evaluated &lt;strong&gt;when the call happens&lt;/strong&gt;, not when the compiler first sees them, so a &lt;code&gt;time()&lt;/code&gt; in there stays fresh. Kamil Tekiela suggested making it a type. Henrik said it wasn't worthy of a full class. Larry Garfield answered: "I really don't understand why people keep saying this. What makes something 'unworthy' of being a class? ... A data construct doesn't need to be as righteous as Thor to be 'worthy' of a class." Then he named the thing Henrik was reaching for: a lazy value, evaluated only when it's read. Henrik agreed that was what he'd been after all along. &lt;em&gt;2 unrelated threads this week, and both of them landed on the word "lazy." Nobody involved was.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Jens has been writing PHP since around the time version 2 was in use, and on Thursday he posted about something beyond a documentation fix for the first time. Why does &lt;code&gt;var_export()&lt;/code&gt; still print the long &lt;code&gt;array(...)&lt;/code&gt; syntax, when that output gets pasted around by PhpStorm and Xdebug all day? There's an RFC for changing it that has been sitting there for 6 years. Larry Garfield linked 3 previous rounds of the same conversation without taking a side. Kamil Tekiela offered the explanation: "IMHO, the two main reasons for the lack of change are apathy and lack of agreement as to what exactly the better syntax is." The constraint he describes is that &lt;code&gt;var_export()&lt;/code&gt; is meant to be &lt;strong&gt;PHP-executable first&lt;/strong&gt; and human-readable second, so as long as the output runs, the function is doing its job. He also named the trap. Change one thing about that output and everyone arrives with everything else they'd like fixed — &lt;em&gt;which is a fair summary of the last 6 years.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Otar Chekurishvili posted a pre-RFC on Monday for 2 opt-in flags in the &lt;code&gt;json&lt;/code&gt; extension, targeting &lt;code&gt;8.7&lt;/code&gt;. One is &lt;code&gt;JSON_ALLOW_COMMENTS&lt;/code&gt; and the other is &lt;code&gt;JSON_ALLOW_TRAILING_COMMAS&lt;/code&gt;, and both would be accepted by &lt;code&gt;json_decode()&lt;/code&gt; and &lt;code&gt;json_validate()&lt;/code&gt;. &lt;strong&gt;Strict JSON stays the default.&lt;/strong&gt; Trailing commas allow exactly 1 after the last element. &lt;em&gt;That's 1 more than JSON allows today, and exactly as many as most of us have typed by accident.&lt;/em&gt; He's proposing 2 separate primary votes so either flag can pass on its own, and says the implementation reuses the existing scanner and grammar rather than preprocessing the input, so error positions survive intact. Larry Garfield asked: "Does this essentially mean JSON5 support? If so, just call it that." Anton Smirnov corrected the name. What's proposed is Microsoft's JSONC, or Nigel Tao's JWCC; real JSON5 would also need single quotes, unquoted keys, infinities and multiline strings, among other things. No reply from Otar yet.&lt;/p&gt;

&lt;p&gt;Alexander Lisachenko wants to fix something about PHP's FFI. Every C value it hands back comes back as the same final class, &lt;code&gt;FFI\CData&lt;/code&gt;. A string pointer, a zval pointer and a raw &lt;code&gt;char&lt;/code&gt; pointer are all the same type to PHP. &lt;em&gt;Which makes FFI strongly typed, in the sense that there is 1 type.&lt;/em&gt; He described the consequence bluntly: "no C struct a binding works with can ever be described to static analysis or an IDE, and CData being final closes off every userland workaround." To get any static typing in his own library he ships 4 separate workarounds, and &lt;code&gt;instanceof&lt;/code&gt; still doesn't work. His proposal is an opt-in class map passed as an options array, in the same shape as &lt;code&gt;SoapClient&lt;/code&gt; takes one, so a registered C type comes back as &lt;strong&gt;your&lt;/strong&gt; class instead of bare &lt;code&gt;CData&lt;/code&gt;. He says it stays inside the &lt;code&gt;ffi&lt;/code&gt; extension and costs nothing when unused. Bob Weinand's is the only reply so far, asking for patience: "don't rush this, write a RFC, and check what actually feels good to use and read."&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;8.6&lt;/code&gt; deprecation vote closed 9 days ago, and one of the items that passed deprecates &lt;code&gt;SplFileObject&lt;/code&gt;'s CSV methods. In the last days of voting Takuya Aramaki pointed out that the &lt;code&gt;READ_CSV&lt;/code&gt; flag was left out, and that &lt;code&gt;setCsvControl()&lt;/code&gt; is the only thing that can configure it — so removing the method leaves the flag stuck on its defaults. Nobody answered him. On Saturday Robert Humphries picked it back up. His reading is that leaving &lt;code&gt;READ_CSV&lt;/code&gt; in place does resolve the original issue, but doesn't achieve the goal of getting CSV handling &lt;strong&gt;out&lt;/strong&gt; of SPL. By his reading of the code there's a second problem. When the default escape character for &lt;code&gt;fgetcsv()&lt;/code&gt; changes, code using &lt;code&gt;READ_CSV&lt;/code&gt; will behave differently across PHP versions with no way to pin it. His conclusion is that &lt;code&gt;READ_CSV&lt;/code&gt; needs deprecating too, and that a migration path should have been part of the proposal. &lt;em&gt;Still no reply.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Eloi Montañés asked the list on Saturday whether abstract class constants are worth an RFC. The idea is to let an abstract class or a trait declare a constant with the &lt;code&gt;abstract&lt;/code&gt; keyword, and require implementers to define one. His examples are a base class that requires a table name and a trait that requires a log tag — things you want fixed at author time rather than changeable at runtime. He points back to a &lt;strong&gt;2017&lt;/strong&gt; thread on the same idea, from before typed constants landed. John Bafford suggested interfaces should get the same treatment, since an interface can already require a property but has no way to require a constant or a static one. Eloi was persuaded, and this morning asked why interfaces have never supported static properties. Larry Garfield answered from experience. He says they considered it while building interface property support for property hooks, and passed for 2 reasons. Object properties cover almost every case and attributes cover the rest, and "static properties are way harder to deal with in the engine, because reasons." &lt;em&gt;He also left a parser problem on the table.&lt;/em&gt; Interfaces already support ordinary constants, so an &lt;code&gt;abstract&lt;/code&gt; keyword may be necessary there regardless.&lt;/p&gt;

&lt;p&gt;Quick hits. Sjoerd Langkemper gave its own page to a proposal that missed the &lt;code&gt;8.6&lt;/code&gt; window. &lt;code&gt;bindec()&lt;/code&gt;, &lt;code&gt;octdec()&lt;/code&gt;, &lt;code&gt;hexdec()&lt;/code&gt; and &lt;code&gt;base_convert()&lt;/code&gt; would throw a &lt;code&gt;ValueError&lt;/code&gt; when you hand them characters that aren't valid for the base, instead of the deprecation notice they've emitted since &lt;code&gt;7.4&lt;/code&gt;. Today &lt;code&gt;hexdec('z')&lt;/code&gt; returns 0. It targets &lt;code&gt;8.7&lt;/code&gt; and has no replies yet. Weilin Du also asked for feedback on tightening 2 INI settings. Right now &lt;code&gt;upload_max_filesize=1GB&lt;/code&gt; can be read as &lt;strong&gt;1 byte&lt;/strong&gt; by the request parser while &lt;code&gt;ini_get()&lt;/code&gt; still reports the string you wrote, &lt;em&gt;which is a spectacular way to lose an afternoon&lt;/em&gt;. His change warns and falls back to the default instead. Jakub Zelenka reads that as incomplete wording in the BC policy rather than a real break. Osama Aldemeery is parking his &lt;code&gt;PREG_THROW_ON_ERROR&lt;/code&gt; RFC until early September, writing: "This has gone quiet, which I'm taking as the freeze crunch and people being busy, not as everyone being fine with it as-is." And 3 releases went out on Thursday. Joe Ferguson shipped PHP &lt;code&gt;8.6.0&lt;/code&gt; beta 1, with beta 2 due on August 27, and Calvin Buckley and Daniel Scherzer followed with &lt;code&gt;8.4.25&lt;/code&gt; and &lt;code&gt;8.5.10&lt;/code&gt; RC 1. &lt;em&gt;Matteo Beccati mentioned in passing that the &lt;code&gt;8.6&lt;/code&gt; branch should be cut on September 22.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's the week in short. &lt;strong&gt;No RFC went to a vote&lt;/strong&gt;, and nothing is in the voting phase at all. A new contributor's &lt;code&gt;array_search_range()&lt;/code&gt; ran into a counter-proposal for a general lazy array slice, and is still a draft. A one-line inconsistency in &lt;code&gt;ini_get_all()&lt;/code&gt; turned into a question about case sensitivity that ended with the author withdrawing a proposal 3 other people then defended. A &lt;code&gt;params&lt;/code&gt; keyword got talked into being a lazy value. Abstract class constants may pick up interfaces. And PHP &lt;code&gt;8.6&lt;/code&gt; beta 1 is out, with beta 2 due &lt;em&gt;next week.&lt;/em&gt; Links to every thread are below. Thanks again to &lt;code&gt;Ballast.now&lt;/code&gt; for supporting this week's episode. We're Artisan Build. See you next week.&lt;/p&gt;

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
    <item>
      <title>This Week In PHP Internals | August 12, 2026</title>
      <dc:creator>Len Woodward</dc:creator>
      <pubDate>Thu, 13 Aug 2026 19:55:59 +0000</pubDate>
      <link>https://dev.to/projektgopher/this-week-in-php-internals-august-12-2026-3ejb</link>
      <guid>https://dev.to/projektgopher/this-week-in-php-internals-august-12-2026-3ejb</guid>
      <description>&lt;p&gt;happened This Week in PHP Internals.&lt;/p&gt;

&lt;p&gt;11 stories this week, so let's get into it. &lt;em&gt;But first,&lt;/em&gt; Your team adopted AI. Everyone says it made them faster. Ballast measures whether that's &lt;strong&gt;true&lt;/strong&gt; — how much faster you're &lt;em&gt;actually&lt;/em&gt; going, and whether what you ship is still holding up. 6.75 times the commits. Durability down 19 points. &lt;em&gt;Now you know.&lt;/em&gt; It runs on &lt;strong&gt;your&lt;/strong&gt; 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 &lt;strong&gt;free&lt;/strong&gt; today. &lt;code&gt;ballast.now&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One correction before the top story. Last week we described the &lt;code&gt;list()&lt;/code&gt; deprecation vote as &lt;strong&gt;deadlocked&lt;/strong&gt; 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 &lt;strong&gt;tied&lt;/strong&gt;, and voting carried on to the finish. He's right, we'll say it properly this week — and thanks, Derick, for keeping us precise.&lt;/p&gt;

&lt;p&gt;This week's top story: the verdict is in on the 35-ballot mass deprecation vote for PHP &lt;code&gt;8.6&lt;/code&gt;. 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 &lt;code&gt;list()&lt;/code&gt; finished on a flat tie — 23 to 23, with 1 abstention — exactly 50 percent, nowhere near two-thirds. Reserving &lt;code&gt;in&lt;/code&gt;, &lt;code&gt;out&lt;/code&gt;, and &lt;code&gt;inout&lt;/code&gt; failed at 8 to 21. The gettext &lt;code&gt;_()&lt;/code&gt; alias survived at 10 to 22. And the &lt;code&gt;dechunk&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;Now last week's cliffhangers. Reserving &lt;code&gt;let&lt;/code&gt; 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 &lt;code&gt;is&lt;/code&gt; passed at 29 to 10, despite Rowan Tommins's warning about the Hamcrest testing library and its 500 million installs. And the &lt;code&gt;define()&lt;/code&gt; 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 &lt;code&gt;SplFileObject&lt;/code&gt; 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 &lt;code&gt;READ_CSV&lt;/code&gt; be deprecated alongside the methods, or that &lt;code&gt;setCsvControl()&lt;/code&gt; stay until a replacement exists. No answer yet — and the item passed at 25 to 5, with 15 abstentions.&lt;/p&gt;

&lt;p&gt;The final 3 ballots of the &lt;code&gt;8.6&lt;/code&gt; season are settled, and they went 2 and 1. Caleb White's pipe assignment operator — &lt;code&gt;|&amp;gt;=&lt;/code&gt; — 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 &lt;code&gt;Duration&lt;/code&gt; and the deprecations, PHP &lt;code&gt;8.6&lt;/code&gt;'s RFC season is &lt;strong&gt;over&lt;/strong&gt; — the beta 1 tag brings the soft freeze this week, and beta 1 itself lands Thursday.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;inference&lt;/strong&gt; — the engine automatically detecting closures that never touch &lt;code&gt;$this&lt;/code&gt; 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 &lt;strong&gt;string&lt;/strong&gt; like "Foo::instanceCall" into an &lt;code&gt;array_map&lt;/code&gt; 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 &lt;code&gt;8.6&lt;/code&gt;, but the engine won't infer anything for you. Mark your closures &lt;code&gt;static&lt;/code&gt; yourself and you get the full benefit.&lt;/p&gt;

&lt;p&gt;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." &lt;em&gt;And in the research footnotes:&lt;/em&gt; 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 &lt;code&gt;8.6&lt;/code&gt; ships — Tim Düsterhus, who's building it, is busy with the release.&lt;/p&gt;

&lt;p&gt;The first RFC aimed past the freeze is already here. Weilin Du proposed &lt;code&gt;IntlRelativeDateTimeFormatter&lt;/code&gt; on Friday, targeting PHP &lt;code&gt;8.7&lt;/code&gt; — 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: &lt;code&gt;8.6&lt;/code&gt; just gained a &lt;code&gt;Duration&lt;/code&gt; 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 &lt;code&gt;Intl&lt;/code&gt; prefix for consistency with the existing &lt;code&gt;intl&lt;/code&gt; extension, and filed modernization under future scope. One suggestion did land immediately: by Saturday the constructor had grown an optional &lt;code&gt;NumberFormatter&lt;/code&gt; parameter, with Weilin reporting: "The implementation is way more smoother than I expected."&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;reified&lt;/strong&gt; 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 — &lt;em&gt;what&lt;/em&gt; Discord? Rob posted channel links; Carlos, a Discord newcomer, still couldn't get in. Larry Garfield finally supplied the address, &lt;code&gt;phpc.chat&lt;/code&gt;, 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." &lt;em&gt;And I can personally vouch for that statement.&lt;/em&gt; Then Monday brought a &lt;strong&gt;third&lt;/strong&gt; 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.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;first message ever&lt;/strong&gt; 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.&lt;/p&gt;

&lt;p&gt;Quick hits. Juris Evertovskis ran a temperature check on &lt;code&gt;isset&lt;/code&gt;: expressions &lt;strong&gt;inside&lt;/strong&gt; the square brackets still throw warnings and deprecations even though &lt;code&gt;isset&lt;/code&gt; 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 &lt;code&gt;session&lt;/code&gt; extension in his sights. And the list has a new face: Sepehr Mahmoudi introduced himself Tuesday with a pull request already open and an &lt;code&gt;array_search_range&lt;/code&gt; idea in hand; mickmackusa pointed him at &lt;code&gt;array_find_key()&lt;/code&gt; and suggested making the case on the list before writing more code, and Yuya Hamada thanked him for the contribution.&lt;/p&gt;

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

</description>
      <category>php</category>
      <category>laravel</category>
      <category>news</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
