<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>#externals</title><link>https://externals.io</link><description>Opening PHP's #internals to the outside</description><pubDate>Mon, 02 Nov 2026 04:43:05 +0000</pubDate><lastBuildDate>Mon, 02 Nov 2026 04:43:05 +0000</lastBuildDate><item><title>[VOTE] [RFC] Case-insensitive extension names in ini_get_all()</title><link>https://externals.io/message/132987</link><description>&lt;p&gt;Hi all,&lt;/p&gt;
&lt;p&gt;The voting process of the Case-insensitive extension names in &lt;code&gt;ini_get_all()&lt;/code&gt; &lt;br&gt;
RFC starts today and ends at Nov 16 00:00:00 UTC.&lt;/p&gt;
&lt;p&gt;RFC: &lt;a href="https://wiki.php.net/rfc/case_insensitive_ini_get_all" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/case_insensitive_ini_get_all&lt;/a&gt; &lt;br&gt;
Discussion thread: &lt;a href="https://externals.io/message/132226" rel="nofollow" target="_blank"&gt;https://externals.io/message/132226&lt;/a&gt;, &lt;a href="https://news-web.php.net/php.internals/132875" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132875&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you, &lt;br&gt;
Weilin Du&lt;/p&gt;
</description><guid>tencent_83B2B59731743FE28804D1AEA3A55BDEB308@qq.com</guid><pubDate>Mon, 02 Nov 2026 02:47:21 +0000</pubDate></item><item><title>[RFC] [VOTE] Throw exception for invalid characters in number base functions</title><link>https://externals.io/message/132986</link><description>&lt;blockquote&gt;
&lt;p&gt;It is now possible to vote on the RFC &amp;quot;Throw exception for invalid characters in number base functions&amp;quot;.&lt;/p&gt;
&lt;p&gt;RFC: &lt;a href="https://wiki.php.net/rfc/throw_error_for_invalid_characters_for_number_base" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/throw_error_for_invalid_characters_for_number_base&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This RFC was accepted with 27 yes votes and 1 no vote.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>eeb62941-7d17-4895-a892-f10c5157c601@app.fastmail.com</guid><pubDate>Sun, 01 Nov 2026 19:49:53 +0000</pubDate></item><item><title>[RFC] PDO binary parameter support</title><link>https://externals.io/message/132985</link><description>&lt;p&gt;Hi Calvin,&lt;/p&gt;
&lt;p&gt;Here are a couple of follow-up notes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;ol start="2"&gt;
&lt;li&gt;The fallback leaves each driver to choose STR or LOB, and STR &lt;br&gt;
corrupts data: pdo_pgsql reads text-format parameters as C strings &lt;br&gt;
(truncated at the first NUL), pdo_mysql loses the _binary introducer. A &lt;br&gt;
per-driver table (native bind, emulated quote, fetch) would pin this down.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;For drivers that use emulated prepares, perhaps we could check string &lt;br&gt;
contents instead and use binary quoting based on that, but that feels slow &lt;br&gt;
and what characters need binary quoting would differ per driver.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Content sniffing can't settle this. A bytea or varbinary value can be valid &lt;br&gt;
text, and text can contain a NUL, so the driver has to be told. It also &lt;br&gt;
doesn't help native prepares: pdo_pgsql sends text-format parameters as C &lt;br&gt;
strings, so they truncate at the first NUL regardless of quoting. That's &lt;br&gt;
the strongest argument for the RFC imho.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Neither representation degrades safely. An unknown type 6 falls to &lt;br&gt;
text in the bundled drivers and pdo_oci, IM001 in pdo_ibm, and a fatal &lt;br&gt;
error in pdo_sqlsrv. A flag only survives where the type is masked with &lt;br&gt;
PDO_PARAM_TYPE(); the emulated-prepare parser, PDO::quote(), the pgsql &lt;br&gt;
quoter, fetch_value() and pdo_sqlsrv all compare the raw value. The flag &lt;br&gt;
works only if core masks it before quoting and fetch overrides; the RFC &lt;br&gt;
should require that, and define what PARAM_INT | PARAM_BINARY does &lt;br&gt;
(ValueError, I'd say).&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Marking this a breaking change for drivers seems reasonable then&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The driver break decides between using a type versus a flag. A new type 6 &lt;br&gt;
is a fatal error in pdo_sqlsrv and IM001 in pdo_ibm until each driver ships &lt;br&gt;
an update. A flag that core masks before quoting allows fetch to fall back &lt;br&gt;
to STR/LOB in any driver that ignores it. I'd go with the flag, and &lt;br&gt;
reject combinations &lt;br&gt;
with INT/BOOL/NULL with a ValueError.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Changing getColumnMeta()'s pdo_type breaks strict comparisons either &lt;br&gt;
way (6 or STR | BINARY). A separate key would avoid that.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I suspect a BC break for things relying on getColumnMeta would happen &lt;br&gt;
regardless of strategy. We could try something like pdo_sqlite's blob key &lt;br&gt;
perhaps if we really want to avoid it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;pdo_sqlite already marks blobs in getColumnMeta()'s &amp;quot;flags&amp;quot; array, which is &lt;br&gt;
a good precedent for leaving pdo_type alone.&lt;/p&gt;
&lt;p&gt;-- &lt;br&gt;
Ilia Alshanetsky &lt;br&gt;
Technologist, CTO, Entrepreneur &lt;br&gt;
E: &lt;a href="mailto:ilia@ilia.ws" rel="nofollow" target="_blank"&gt;ilia@ilia.ws&lt;/a&gt; &lt;br&gt;
T: @iliaa &lt;br&gt;
B: &lt;a href="http://ilia.ws" rel="nofollow" target="_blank"&gt;http://ilia.ws&lt;/a&gt;&lt;/p&gt;
</description><guid>CALkpNnQDNfLMpC2+77U5hi8n0JU1TS83YQfVmrC2UtOcczqCGw@mail.gmail.com</guid><pubDate>Sun, 01 Nov 2026 16:39:20 +0000</pubDate></item><item><title>[RFC] Scope</title><link>https://externals.io/message/132984</link><description>&lt;p&gt;I did go back and forth with terminology, but eventually landed on Scope. The term is used elsewhere in php documentation, for example Closure::bind() etc, but context is used much more.&lt;/p&gt;
&lt;p&gt;fiber-interop/api on packagist has a Scope polyfill, and I don't think personally that WeakMap was hard to get right for scoped services. It takes getting used to, but it seems better than storing data directly in the scope object.&lt;/p&gt;
&lt;p&gt;With regards, &lt;br&gt;
Frode Børli&lt;/p&gt;
&lt;p&gt;Sendt fra Outlook for iOS&lt;a href="https://aka.ms/o0ukef"&gt;https://aka.ms/o0ukef&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;From: Rowan Tommins [IMSoP] &lt;a href="mailto:imsop.php@rwec.co.uk"&gt;imsop.php@rwec.co.uk&lt;/a&gt; &lt;br&gt;
Sent: Sunday, 01 November 2026 15:26:40 &lt;br&gt;
To: &lt;a href="mailto:internals@lists.php.net" rel="nofollow" target="_blank"&gt;internals@lists.php.net&lt;/a&gt; &lt;a href="mailto:internals@lists.php.net"&gt;internals@lists.php.net&lt;/a&gt; &lt;br&gt;
Subject: Re: [PHP-DEV] [RFC] Scope&lt;/p&gt;
&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to start the discussion on a new RFC:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hi Frode,&lt;/p&gt;
&lt;p&gt;I'm really happy to see this as an independent, focussed, RFC, which can hopefully fit well with the other async-related proposals being worked on.&lt;/p&gt;
&lt;p&gt;In early versions of the &amp;quot;True Async&amp;quot; RFC, Edmond Dantes included a complex API for attaching data to coroutine scopes, and I argued at the time that it could be simplified, and more complex structures built on top of it later. It looks like that's exactly the approach taken here, providing only the parts that are essentially impossible in userland.&lt;/p&gt;
&lt;p&gt;I do share Larry's concern that some of the common patterns using WeakMap will be hard to get right, but maybe that can be solved by additional helper classes and functions which might have other uses anyway?&lt;/p&gt;
&lt;p&gt;The only slightly trivial reaction I had was to the name: variable scope is something we talk about so often, that I can see &amp;quot;variables tied to the current Scope&amp;quot; confusing people. Naming things is notoriously hard, but I note that a lot of the other languages you reference use the word &amp;quot;context&amp;quot; instead, and wonder if you'd considered that?&lt;/p&gt;
&lt;p&gt;Thanks,&lt;/p&gt;
&lt;p&gt;-- &lt;br&gt;
Rowan Tommins &lt;br&gt;
[IMSoP]&lt;/p&gt;
</description><guid>AS8PR08MB7339473A56DA4D25AB4DF7F7D96B2@AS8PR08MB7339.eurprd08.prod.outlook.com</guid><pubDate>Sun, 01 Nov 2026 14:31:26 +0000</pubDate></item><item><title>[RFC] Scope</title><link>https://externals.io/message/132983</link><description>&lt;blockquote&gt;
&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to start the discussion on a new RFC:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt; &lt;a href="https://wiki.php.net/rfc/scope"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hi Frode,&lt;/p&gt;
&lt;p&gt;I'm really happy to see this as an independent, focussed, RFC, which can &lt;br&gt;
hopefully fit well with the other async-related proposals being worked on.&lt;/p&gt;
&lt;p&gt;In early versions of the &amp;quot;True Async&amp;quot; RFC, Edmond Dantes included a &lt;br&gt;
complex API for attaching data to coroutine scopes, and I argued at the &lt;br&gt;
time that it could be simplified, and more complex structures built on &lt;br&gt;
top of it later. It looks like that's exactly the approach taken here, &lt;br&gt;
providing only the parts that are essentially impossible in userland.&lt;/p&gt;
&lt;p&gt;I do share Larry's concern that some of the common patterns using &lt;br&gt;
WeakMap will be hard to get right, but maybe that can be solved by &lt;br&gt;
additional helper classes and functions which might have other uses anyway?&lt;/p&gt;
&lt;p&gt;The only slightly trivial reaction I had was to the name: variable scope &lt;br&gt;
is something we talk about so often, that I can see &amp;quot;variables tied to &lt;br&gt;
the current Scope&amp;quot; confusing people. Naming things is notoriously hard, &lt;br&gt;
but I note that a lot of the other languages you reference use the word &lt;br&gt;
&amp;quot;context&amp;quot; instead, and wonder if you'd considered that?&lt;/p&gt;
&lt;p&gt;Thanks,&lt;/p&gt;
&lt;p&gt;-- &lt;br&gt;
Rowan Tommins &lt;br&gt;
[IMSoP]&lt;/p&gt;
</description><guid>562250f6-6f9b-4b19-9774-0f8e491ed5bb@rwec.co.uk</guid><pubDate>Sun, 01 Nov 2026 14:26:40 +0000</pubDate></item><item><title>[RFC][Discussion] Add PASSWORD_BCRYPT_WRAP</title><link>https://externals.io/message/132982</link><description>&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The section on “bcrypt-sha256” is very vague in how your construction &lt;br&gt;
is better. Given that both bcrypt-sha256 and your bcrypt-wrap (with &lt;br&gt;
SHA-512) use a HMAC construction using the (BCrypt) salt as a key as the &lt;br&gt;
pre-hash, folks will rightfully wonder how the bcrypt-wrap construction &lt;br&gt;
is better than that of bcrypt-sha256 (other than using a different hash &lt;br&gt;
function) and should not be required to “reverse engineer” the &lt;br&gt;
differences.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Recently two new password hashes were proposed, both with the goal of solving bcrypt's 72-byte limit and failure to handle null-bytes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PASSWORD_BCRYPT_WRAP &lt;a href="https://wiki.php.net/rfc/password_bcrypt_wrap" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/password_bcrypt_wrap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PASSWORD_BCRYPT_SHA256 &lt;a href="https://wiki.php.net/rfc/bcrypt_sha256" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/bcrypt_sha256&lt;/a&gt; (proposed by me)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both prehash the password before passing them to bcrypt. &lt;br&gt;
• BCRYPT_SHA256 uses the same algorithm as Python's passlib. That provides interoperability with that library. It also means we cannot deviate from that algorithm without giving up that interoperability. &lt;br&gt;
• BCRYPT_SHA256 is simpler and adds less code to PHP. &lt;br&gt;
• BCRYPT_WRAP supports two prehashing algorithms. &lt;br&gt;
• Both use the salt as the key, but in a technically different way. BCRYPT_WRAP decodes the base64-encoded salt, BCRYPT_SHA256 normalizes the text version of the salt. &lt;br&gt;
• The text representation of the hash differs: BCRYPT_WRAP follows the PHC string format and is slightly longer than BCRYPT_SHA256. &lt;br&gt;
I think both RFC with all three proposed prehashing methods are sufficiently secure. For security I see no reason to prefer one over the other.&lt;/p&gt;
&lt;p&gt;Adding one new algorithm would be sufficient. Cryptographic agility within the hashing algorithm is not necesssary; users can move to another hashing algorithm such as Argon2. Both hash formats have a version field, making it possible to make backwards compatible changes.&lt;/p&gt;
&lt;p&gt;It is unfortunate that we now have two RFCs that are so similar. Voting on them in isolation could result in an undesirable outcome.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>300c67c4-f1fd-412c-b323-543a5df27154@app.fastmail.com</guid><pubDate>Sun, 01 Nov 2026 11:19:38 +0000</pubDate></item><item><title>Request for RFC karma</title><link>https://externals.io/message/132981</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to request RFC karma for my PHP Wiki account.&lt;/p&gt;
&lt;p&gt;Wiki username: artukrainskiy&lt;/p&gt;
&lt;p&gt;I'm preparing an RFC for native multi-pattern string search and replacement &lt;br&gt;
using Aho-Corasick, with two new classes: Str\Matcher and Str\Replacer.&lt;/p&gt;
&lt;p&gt;I've opened a draft implementation PR: &lt;br&gt;
&lt;a href="https://github.com/php/php-src/pull/25122" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/25122&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Benchmarks and analysis are available here: &lt;br&gt;
&lt;a href="https://github.com/ArtUkrainskiy/php-src-bench/tree/main/reports/multi-pattern-search" rel="nofollow" target="_blank"&gt;https://github.com/ArtUkrainskiy/php-src-bench/tree/main/reports/multi-pattern-search&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'd like to create a draft RFC to document the proposal and discuss the API &lt;br&gt;
and design with the community.&lt;/p&gt;
&lt;p&gt;-- &lt;br&gt;
Best regards, &lt;br&gt;
Artem Ukrainskiy&lt;/p&gt;
</description><guid>CAPen=wHc=-LLO-Mjmo00p2zTpu4whtbTk00nmVaSvNU684oZHQ@mail.gmail.com</guid><pubDate>Sun, 01 Nov 2026 11:13:42 +0000</pubDate></item><item><title>RFC karma request: grapheme_str_pad()</title><link>https://externals.io/message/132980</link><description>&lt;p&gt;Hi Chris&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'd like to request RFC karma on the wiki to propose a new function, &lt;br&gt;
grapheme_str_pad(). My wiki username is: chrisabner&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;RFC karma was granted. Good luck!&lt;/p&gt;
&lt;p&gt;Ilija&lt;/p&gt;
</description><guid>1110aef5-d5ae-4c5b-a953-268af81dd39c@gmail.com</guid><pubDate>Sat, 31 Oct 2026 23:42:27 +0000</pubDate></item><item><title>[VOTE] [RFC] Case-insensitive extension names in ini_get_all()</title><link>https://externals.io/message/132979</link><description>&lt;p&gt;Hi all,&lt;/p&gt;
&lt;p&gt;Nice to write you this email. This is an intent-to-vote email to &lt;br&gt;
announce the &amp;quot;Case-insensitive extension names in &lt;code&gt;ini_get_all()&lt;/code&gt;&amp;quot; &lt;br&gt;
RFC will be voted two days later, which is 2 Nov.&lt;/p&gt;
&lt;p&gt;RFC: &lt;a href="https://wiki.php.net/rfc/case_insensitive_ini_get_all" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/case_insensitive_ini_get_all&lt;/a&gt; &lt;br&gt;
RFC discussion thread: &lt;a href="https://news-web.php.net/php.internals/132875" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132875&lt;/a&gt; &lt;br&gt;
Initial discussion thread: &lt;a href="https://externals.io/message/132226" rel="nofollow" target="_blank"&gt;https://externals.io/message/132226&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I understand this may sounds like a very minor change to be vote &lt;br&gt;
on. However, considering some objected the change, the only way &lt;br&gt;
to implement this BC break is to go through a RFC process.&lt;/p&gt;
&lt;p&gt;Thank you, &lt;br&gt;
Weilin&lt;/p&gt;
</description><guid>tencent_E1EF01D9AC4B03BA70713282345788520707@qq.com</guid><pubDate>Fri, 30 Oct 2026 15:41:32 +0000</pubDate></item><item><title>Request lifecycle hooks for SAPIs that serve multiple requests per script (like FrankenPHP in worker mode)</title><link>https://externals.io/message/132978</link><description>&lt;p&gt;Hi Larry,&lt;/p&gt;
&lt;p&gt;Sorry for the top post :/&lt;/p&gt;
&lt;p&gt;We're still early in the process of Scope adoption, and Scope will &lt;br&gt;
have to interact with existing worker modes anyway, because their APIs &lt;br&gt;
are already widely used in the wild.&lt;/p&gt;
&lt;p&gt;Scope will also have to deal with what my proposal solves: letting &lt;br&gt;
extensions detect when the response has been sent (currently, a Scope &lt;br&gt;
lives as long as something references it, which can be long after the &lt;br&gt;
request is finished), and resetting the state tied to the request: &lt;br&gt;
sessions (as explained in the Scope RFC), output buffers, the URL &lt;br&gt;
rewriter, etc.&lt;/p&gt;
&lt;p&gt;I propose combining the two: once Scope is accepted and implemented, &lt;br&gt;
php_request_begin() will create a new scope, and SAPIs will get it for &lt;br&gt;
free. When the HTTP response is finished, SAPIs call &lt;br&gt;
php_request_end(), so extensions have a hook to do what they want when &lt;br&gt;
a request terminates, even if the Scope survives because it is still &lt;br&gt;
referenced.&lt;/p&gt;
&lt;p&gt;For instance, with FrankenPHP:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;?php
$scope = null;
while (frankenphp_handle_request(function () use (&amp;amp;$scope) {
    // C function php_request_begin() has been called by
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;FrankenPHP's SAPI: this callback runs in a new scope &lt;br&gt;
$scope = Scope::getCurrent(); // leaked on purpose &lt;br&gt;
})) { &lt;br&gt;
// php_request_end() called by FrankenPHP: the session is &lt;br&gt;
written and extensions flushed their data, even though $scope is still &lt;br&gt;
alive &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;The user-space and engine-space lifetimes stay in sync because the &lt;br&gt;
SAPI drives both.&lt;/p&gt;
&lt;p&gt;Both proposals work well together. It also allows continuing work on &lt;br&gt;
both (almost) independently and lets them ship at their own pace, &lt;br&gt;
regardless of the result of their respective votes.&lt;/p&gt;
</description><guid>CADU7aoun4cOyu57vYxXttuUsfT8x1R67tyAfUKo5Yo3ow4Dm-w@mail.gmail.com</guid><pubDate>Fri, 30 Oct 2026 14:22:40 +0000</pubDate></item><item><title>Request lifecycle hooks for SAPIs that serve multiple requests per script (like FrankenPHP in worker mode)</title><link>https://externals.io/message/132977</link><description>&lt;blockquote&gt;
&lt;p&gt;After an off-list discussion with Tim Düsterhus, I'm retracting some &lt;br&gt;
of the examples from my first email: &lt;code&gt;http_get_last_response_headers()&lt;/code&gt;, &lt;br&gt;
the libxml errors, &lt;code&gt;error_get_last()&lt;/code&gt; and &lt;code&gt;strtok()&lt;/code&gt;. They don't depend on &lt;br&gt;
the incoming HTTP request, so a worker SAPI shouldn't reset them &lt;br&gt;
between &amp;quot;logical&amp;quot; requests. Like any other state shared in worker &lt;br&gt;
mode, userland can clear them when needed with the existing functions &lt;br&gt;
(http_clear_last_response_headers(), &lt;code&gt;libxml_clear_errors()&lt;/code&gt;, &lt;br&gt;
&lt;code&gt;error_clear_last()&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The rule I'm proposing is narrower: reset only the state built from &lt;br&gt;
the incoming request or tied to its response. The session module and &lt;br&gt;
&lt;code&gt;output_add_rewrite_var()&lt;/code&gt; still fall under it.&lt;/p&gt;
&lt;p&gt;The main point of the proposal stands: hooks for &amp;quot;logical&amp;quot; requests &lt;br&gt;
give extensions one abstraction that works with every SAPI that has a &lt;br&gt;
worker mode, instead of special-casing each one.&lt;/p&gt;
&lt;p&gt;FrankenPHP will follow the same rule in its next release.&lt;/p&gt;
&lt;p&gt;Tim suggested a short RFC. I'll write it soon.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Bottom post, please. :-)&lt;/p&gt;
&lt;p&gt;I'm still a bit fuzzy on how this would interact with Scopes.  Specifically, I presume we would want the user-space definition of &amp;quot;request lifetime&amp;quot; and the engine-space definition of &amp;quot;request lifetime&amp;quot; to be in sync.  But as you note, Scopes as proposed don't have a clear and obvious The End that can correspond to firing the request end hook.  So what would that coordination look like?  Some contrived code samples would probably help.&lt;/p&gt;
&lt;p&gt;--Larry Garfield&lt;/p&gt;
</description><guid>9aff8431-1739-47b1-8917-39d7c6586eaa@app.fastmail.com</guid><pubDate>Fri, 30 Oct 2026 13:42:23 +0000</pubDate></item><item><title>Request lifecycle hooks for SAPIs that serve multiple requests per script (like FrankenPHP in worker mode)</title><link>https://externals.io/message/132976</link><description>&lt;p&gt;After an off-list discussion with Tim Düsterhus, I'm retracting some &lt;br&gt;
of the examples from my first email: &lt;code&gt;http_get_last_response_headers()&lt;/code&gt;, &lt;br&gt;
the libxml errors, &lt;code&gt;error_get_last()&lt;/code&gt; and &lt;code&gt;strtok()&lt;/code&gt;. They don't depend on &lt;br&gt;
the incoming HTTP request, so a worker SAPI shouldn't reset them &lt;br&gt;
between &amp;quot;logical&amp;quot; requests. Like any other state shared in worker &lt;br&gt;
mode, userland can clear them when needed with the existing functions &lt;br&gt;
(http_clear_last_response_headers(), &lt;code&gt;libxml_clear_errors()&lt;/code&gt;, &lt;br&gt;
&lt;code&gt;error_clear_last()&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The rule I'm proposing is narrower: reset only the state built from &lt;br&gt;
the incoming request or tied to its response. The session module and &lt;br&gt;
&lt;code&gt;output_add_rewrite_var()&lt;/code&gt; still fall under it.&lt;/p&gt;
&lt;p&gt;The main point of the proposal stands: hooks for &amp;quot;logical&amp;quot; requests &lt;br&gt;
give extensions one abstraction that works with every SAPI that has a &lt;br&gt;
worker mode, instead of special-casing each one.&lt;/p&gt;
&lt;p&gt;FrankenPHP will follow the same rule in its next release.&lt;/p&gt;
&lt;p&gt;Tim suggested a short RFC. I'll write it soon.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello internals,&lt;/p&gt;
&lt;p&gt;As you may know, FrankenPHP and some other SAPIs (like the &lt;br&gt;
experimental ones written in Rust) have optional support for a &amp;quot;worker &lt;br&gt;
mode&amp;quot;. The main idea behind these worker modes is to use long-running &lt;br&gt;
scripts, started when the web server starts, to handle multiple HTTP &lt;br&gt;
requests in a loop.&lt;/p&gt;
&lt;p&gt;This allows keeping states in memory across requests - such as the &lt;br&gt;
Composer autoloader or Symfony and Laravel services - instead of &lt;br&gt;
re-computing them at the beginning of each new request. This also &lt;br&gt;
allows maintaining persistent connections to remote services across &lt;br&gt;
requests.&lt;/p&gt;
&lt;p&gt;Worker mode dramatically improves performance, at the cost of no &lt;br&gt;
longer isolating state between requests and losing the memory leak &lt;br&gt;
tolerance provided by the traditional &amp;quot;fire and forget&amp;quot; model. This &lt;br&gt;
mode has become increasingly popular since the release of FrankenPHP, &lt;br&gt;
and is now natively supported by a large part of the ecosystem &lt;br&gt;
(Symfony, Laravel, Yii...).&lt;/p&gt;
&lt;p&gt;Currently, the engine and extensions have no knowledge of this, and &lt;br&gt;
have no way to detect when a &amp;quot;real&amp;quot; HTTP request starts or ends. As &lt;br&gt;
expected, they are only aware of the start (and end) of the main, &lt;br&gt;
long-running script. FrankenPHP (and other SAPIs with a similar mode) &lt;br&gt;
reset &amp;quot;real HTTP request&amp;quot; related data by poking into the engine and &lt;br&gt;
first-party extensions &lt;br&gt;
(&lt;a href="https://github.com/php/frankenphp/blob/7f50be9d86261bf7cff9b051ab4fb572e95020ed/frankenphp.c#L400-L646" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/blob/7f50be9d86261bf7cff9b051ab4fb572e95020ed/frankenphp.c#L400-L646&lt;/a&gt;). &lt;br&gt;
This approach is fragile, and the internal code resetting these states &lt;br&gt;
can change without warning in a new PHP version.&lt;/p&gt;
&lt;p&gt;Each omission results in a cross-request leak or a memory safety bug. &lt;br&gt;
FrankenPHP fixed several of them this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a session ID leaking to other clients when ext/session is a shared &lt;br&gt;
module, because FrankenPHP can only reset the session globals when it &lt;br&gt;
is built against the session headers: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-v3ph-cgqh-r8p5" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-v3ph-cgqh-r8p5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a use-after-free of &lt;a href="php://temp" rel="nofollow" target="_blank"&gt;php://temp&lt;/a&gt; streams, because nothing releases &lt;br&gt;
SG(request_info).request_body between worker requests and FrankenPHP's &lt;br&gt;
own cleanup freed streams it didn't own: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-cm3q-jw2q-9rh5" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-cm3q-jw2q-9rh5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a double free because sapi_deactivate() frees &lt;br&gt;
SG(request_info).content_type_dup and current_user without clearing &lt;br&gt;
them (fixed for PHP 8.6: &lt;a href="https://github.com/php/php-src/pull/22974" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/22974&lt;/a&gt;): &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-h764-4wh7-m7j2" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-h764-4wh7-m7j2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http_get_last_response_headers()&lt;/code&gt; returning headers fetched by a &lt;br&gt;
previous request: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-pmvg-8483-mw84" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-pmvg-8483-mw84&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxml_get_errors()&lt;/code&gt; returning errors of a previous request, with &lt;br&gt;
parse-error fragments and server paths: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-4gfw-9v29-gp9h" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-4gfw-9v29-gp9h&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Third-party extensions detect the boundaries themselves, each in its &lt;br&gt;
own way. Xdebug and the Datadog profiler replace sapi_module.activate &lt;br&gt;
and sapi_module.deactivate when the SAPI is FrankenPHP. Datadog's &lt;br&gt;
tracer and AppSec, and New Relic in an open pull request, hook &lt;br&gt;
frankenphp_handle_request(). Blackfire's Symfony bridge, Tideways and &lt;br&gt;
Sentry wrap each request with start and stop calls in userland.&lt;/p&gt;
&lt;p&gt;Calling RSHUTDOWN and RINIT between worker requests doesn't work: &lt;br&gt;
these handlers mix state that needs resetting with state the script &lt;br&gt;
keeps. For instance, the standard extension's RSHUTDOWN releases the &lt;br&gt;
&lt;code&gt;strtok()&lt;/code&gt; state, but also destroys &lt;code&gt;register_tick_function()&lt;/code&gt; callbacks &lt;br&gt;
and user stream filters. The session extension's RSHUTDOWN writes and &lt;br&gt;
closes the session, but also frees the save handlers registered at &lt;br&gt;
boot. The libxml extension's RSHUTDOWN drops the external entity &lt;br&gt;
loader. Only each extension's maintainers know which of their globals &lt;br&gt;
belong to which kind.&lt;/p&gt;
&lt;p&gt;I'd like to add two optional module hooks, called by the SAPI between &lt;br&gt;
two logical requests of the same script:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;request_end: release the state tied to the finished request, but &lt;br&gt;
keep everything still reachable from userland;&lt;/li&gt;
&lt;li&gt;request_begin: set up the next request once its headers and &lt;br&gt;
superglobals are available (&lt;a href="http://session.auto" rel="nofollow" target="_blank"&gt;session.auto&lt;/a&gt;_start, Xdebug's triggers).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two engine functions, php_request_end() and php_request_begin(), would &lt;br&gt;
run the output and SAPI steps that worker SAPIs copy today from &lt;br&gt;
php_request_shutdown() and php_request_startup(), import the &lt;br&gt;
superglobals of the new request (except $_ENV, which comes from the &lt;br&gt;
process), set the execution timer, and call the hooks.&lt;/p&gt;
&lt;p&gt;Releasing the request body takes two small changes: &lt;a href="php://input" rel="nofollow" target="_blank"&gt;php://input&lt;/a&gt; &lt;br&gt;
streams hold a reference to the body, and freeing the body, for &lt;br&gt;
instance when the script closes it, clears &lt;br&gt;
SG(request_info).request_body. Core extensions would implement the &lt;br&gt;
hooks first; third-party extensions could adopt them at their pace. &lt;br&gt;
SAPIs that don't call these functions see no behavior change.&lt;/p&gt;
&lt;p&gt;I drafted a working patch for master, with the standard and session &lt;br&gt;
hooks: &lt;a href="https://github.com/dunglas/php-src/tree/request-boundary-hooks" rel="nofollow" target="_blank"&gt;https://github.com/dunglas/php-src/tree/request-boundary-hooks&lt;/a&gt;. &lt;br&gt;
FrankenPHP doesn't build against master yet, so I tested it with a &lt;br&gt;
patched version of FrankenPHP and it works.&lt;/p&gt;
&lt;p&gt;As this is an internal API with no userland or BC impact, an RFC isn't &lt;br&gt;
strictly needed.&lt;/p&gt;
&lt;p&gt;I made a similar but broader proposal almost 3 years ago &lt;br&gt;
(&lt;a href="https://externals.io/message/122027" rel="nofollow" target="_blank"&gt;https://externals.io/message/122027&lt;/a&gt;). I think time has shown that &lt;br&gt;
worker modes are here to stay, and this less intrusive proposal could &lt;br&gt;
fix several maintenance issues affecting the whole ecosystem.&lt;/p&gt;
&lt;p&gt;So, I would like your opinion on this before working more on it.&lt;/p&gt;
&lt;h2&gt;Best,&lt;/h2&gt;
&lt;p&gt;Kévin Dunglas&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dunglas.dev" rel="nofollow" target="_blank"&gt;https://dunglas.dev&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CADU7aou327fqatx+1rcTNDWSDAGdo66Jncb3ObZAXbDWSCGFuQ@mail.gmail.com</guid><pubDate>Fri, 30 Oct 2026 12:51:03 +0000</pubDate></item><item><title>[RFC][Discussion] Add PASSWORD_BCRYPT_WRAP</title><link>https://externals.io/message/132975</link><description>&lt;blockquote&gt;
&lt;p&gt;RFC link: &lt;a href="https://wiki.php.net/rfc/password_bcrypt_wrap" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/password_bcrypt_wrap&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Supports two prehash primitives, chosen through a prehash option: cshake256 (default) and sha512 (using HMAC construct).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;PASSWORD_BCRYPT_WRAP supports two prehash algorithms. The prehash can be supplied in a hash option. Another possible solution is to create two password_hash algorithms, e.g. PASSWORD_BCRYPT_CSHAKE and PASSWORD_BCRYPT_SHA512.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>9aadf3b9-ba6f-4c1a-a3cb-1785cf580e2e@app.fastmail.com</guid><pubDate>Fri, 30 Oct 2026 12:43:59 +0000</pubDate></item><item><title>[RFC] Opt-in JSON Comments and Trailing Commas</title><link>https://externals.io/message/132974</link><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I intend to open the vote on this RFC on Monday, 2 November 2026, at &lt;br&gt;
12:00 UTC. The vote will end on Monday, 16 November 2026, at 12:00 UTC.&lt;/p&gt;
&lt;p&gt;There are two primary votes, one for each flag. Each vote needs a 2/3 &lt;br&gt;
majority.&lt;/p&gt;
&lt;p&gt;Otar&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello internals,&lt;/p&gt;
&lt;p&gt;I want to start the discussion of the RFC &amp;quot;Opt-in JSON Comments and &lt;br&gt;
Trailing Commas&amp;quot;: &lt;br&gt;
&lt;a href="https://wiki.php.net/rfc/json_comments_trailing_commas"&gt;https://wiki.php.net/rfc/json_comments_trailing_commas&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The RFC adds two independent opt-in flags for &lt;code&gt;json_decode()&lt;/code&gt; and &lt;br&gt;
&lt;code&gt;json_validate()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JSON_ALLOW_COMMENTS accepts // line comments and /* block comments &lt;br&gt;
*/.&lt;/li&gt;
&lt;li&gt;JSON_ALLOW_TRAILING_COMMAS accepts one comma after the last item &lt;br&gt;
of a &lt;br&gt;
non-empty array or object.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Strict JSON stays the default. &lt;code&gt;json_encode()&lt;/code&gt; does not change.&lt;/p&gt;
&lt;p&gt;This RFC follows the pre-RFC thread: &lt;br&gt;
&lt;a href="https://news-web.php.net/php.internals/132236"&gt;https://news-web.php.net/php.internals/132236&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for the feedback in that thread. The RFC now answers it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The RFC does not add JSON5. It compares the two flags with JSON5, &lt;br&gt;
JSONC and JWCC (Larry, Anton).&lt;/li&gt;
&lt;li&gt;The RFC keeps two flags, not one JSON_ALLOW_JSONC flag. The JSONC &lt;br&gt;
specification is a draft, and it makes trailing commas optional. The&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;section &amp;quot;Rejected Features&amp;quot; gives all reasons (Tim).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The RFC includes test results and performance measurements.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The implementation is here: &lt;br&gt;
&lt;a href="https://github.com/php/php-src/pull/23336"&gt;https://github.com/php/php-src/pull/23336&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The RFC has two primary votes, one for each flag. Each vote needs a &lt;br&gt;
2/3  &lt;br&gt;
majority.&lt;/p&gt;
&lt;p&gt;All feedback is welcome.&lt;/p&gt;
&lt;p&gt;Otar&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I am forced to agree with Tim. This is a very tight RFC, and I have no &lt;br&gt;
remaining objections to it. Nicely done!&lt;/p&gt;
&lt;p&gt;--Larry Garfield&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>6aaf55fe20490d2385f799fbdc5e2856794a235c@hey.com</guid><pubDate>Fri, 30 Oct 2026 12:22:58 +0000</pubDate></item><item><title>[RFC][Discussion] Add PASSWORD_BCRYPT_WRAP</title><link>https://externals.io/message/132973</link><description>&lt;blockquote&gt;
&lt;p&gt;I'm happy to correct vagueness, especially if you can point to the unclear &lt;br&gt;
piece of text. However, you are wrong on multiple counts here, and the &lt;br&gt;
answer as to why is in those exact last words in the quote: domain &lt;br&gt;
separation from naked hashes. &lt;br&gt;
Not only is there domain separation from naked hashes, there's domain &lt;br&gt;
separation between the Bcrypt and prehash salts (and even further than &lt;br&gt;
that).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perhaps it would be useful to add to the RFC a non-technical explanation of how hash shucking works, and how adding salt or pepper at the right stage protects against it.&lt;/p&gt;
&lt;p&gt;I attempted to do that in the previous discussion here, based on my own limited understanding: &lt;a href="https://externals.io/message/132784#132850" rel="nofollow" target="_blank"&gt;https://externals.io/message/132784#132850&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Hi Andrey,&lt;/p&gt;
&lt;p&gt;Thanks for the carefully designed RFC. It seems like a useful addition.&lt;/p&gt;
&lt;p&gt;Rowan Tommins &lt;br&gt;
[IMSoP]&lt;/p&gt;
</description><guid>B37AFDA8-E53F-42A5-BA1A-B8D5012DA9F1@rwec.co.uk</guid><pubDate>Fri, 30 Oct 2026 10:22:37 +0000</pubDate></item><item><title>GitHub access request</title><link>https://externals.io/message/132972</link><description>&lt;p&gt;Hello,&lt;/p&gt;
&lt;p&gt;I would like access to php-src in GitHub. I would like to merge my own approved pull requests, and review other people's pull requests. I have previously done some work on the curl extension and I think it would be a good idea to register myself as code owner for that extension, so that I can review merge requests related to curl.&lt;/p&gt;
&lt;p&gt;There's a form to request access, but it gave an error since I already have a PHP account (sjoerd). My GitHub username is Sjord.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>73808c95-e7ba-49b2-a820-506be6cea9aa@app.fastmail.com</guid><pubDate>Fri, 30 Oct 2026 09:55:21 +0000</pubDate></item><item><title>[RFC][Discussion] Add PASSWORD_BCRYPT_WRAP</title><link>https://externals.io/message/132971</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'd like to open the discussion on a new password hashing algorithm &lt;br&gt;
that &lt;br&gt;
I've been working on, named bcrypt-wrap.&lt;/p&gt;
&lt;p&gt;RFC link: &lt;a href="https://wiki.php.net/rfc/password_bcrypt_wrap" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/password_bcrypt_wrap&lt;/a&gt; &lt;br&gt;
Pull request: &lt;a href="https://github.com/php/php-src/pull/25040" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/25040&lt;/a&gt; (just pushed &lt;br&gt;
it, CI &lt;br&gt;
still running)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thank you for the RFC and entertaining my questions in Discord. As &lt;br&gt;
promised, I want to put the points onto the list for public record:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Can you please add a (pseudo) code description of your construction to &lt;br&gt;
the RFC? Prose is needlessly ambiguous as also evidenced by Kamil’s &lt;br&gt;
misunderstanding.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The section on “bcrypt-sha256” is very vague in how your construction &lt;br&gt;
is better. Given that both bcrypt-sha256 and your bcrypt-wrap (with &lt;br&gt;
SHA-512) use a HMAC construction using the (BCrypt) salt as a key as the &lt;br&gt;
pre-hash, folks will rightfully wonder how the bcrypt-wrap construction &lt;br&gt;
is better than that of bcrypt-sha256 (other than using a different hash &lt;br&gt;
function) and should not be required to “reverse engineer” the &lt;br&gt;
differences.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>4c7622fc7ad284494d0079cf31ddbc9a@bastelstu.be</guid><pubDate>Fri, 30 Oct 2026 08:36:23 +0000</pubDate></item><item><title>[RFC][Discussion] Add PASSWORD_BCRYPT_WRAP</title><link>https://externals.io/message/132970</link><description>&lt;p&gt;Hi Kamil,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'm rather against it. Your proposed implementation decreases security &lt;br&gt;
of bcrypt implementation for small and dubious gains. The input space &lt;br&gt;
is decreased from 2^576 to 2^432, which is a magnitude of 2^144. Sure, &lt;br&gt;
these are astronomical values, but it's a significant decrease &lt;br&gt;
nonetheless.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sorry, but this is complete nonsense. A prehash doesn't reduce Bcrypt's &lt;br&gt;
security or input space, and the &amp;quot;dubious gains&amp;quot; are masking all of &lt;br&gt;
Bcrypt's limitations on inputs.&lt;/p&gt;
&lt;p&gt;Additionally, your implementation suffers from hash shucking. OWASP&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;explicitly warns about doing it the way you are doing it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Just using pure SHA-512, ( i.e. bcrypt(base64(sha512($password))), &lt;br&gt;
$salt, $cost)) is a dangerous practice and is as secure as just using pure &lt;br&gt;
SHA-512.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html" rel="nofollow" target="_blank"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's not how I'm doing it. Not even close.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You mention HMAC, but it's a bit vague and looking at the &lt;br&gt;
implementation, I believe you use the public salt as a secret key. &lt;br&gt;
This may obfuscate the hash, but as I understand it, it does not make &lt;br&gt;
pre-hashing safe. In fact the blog which I assume you have looked at &lt;br&gt;
before (&lt;a href="https://soatok.blog/2024/11/27/beyond-bcrypt/" rel="nofollow" target="_blank"&gt;https://soatok.blog/2024/11/27/beyond-bcrypt/&lt;/a&gt;) describes the &lt;br&gt;
problems in detail:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can avoid hash shucking by using HMAC with a static key–either &lt;br&gt;
universal for all deployments of your software, or unique per application.&lt;/p&gt;
&lt;p&gt;It doesn’t really matter which you choose; all you really need from it is &lt;br&gt;
domain separation from naked hashes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm happy to correct vagueness, especially if you can point to the unclear &lt;br&gt;
piece of text. However, you are wrong on multiple counts here, and the &lt;br&gt;
answer as to why is in those exact last words in the quote: domain &lt;br&gt;
separation from naked hashes. &lt;br&gt;
Not only is there domain separation from naked hashes, there's domain &lt;br&gt;
separation between the Bcrypt and prehash salts (and even further than &lt;br&gt;
that).&lt;/p&gt;
&lt;p&gt;And while I have indeed read Soatok's blog, the insinuation that it's the &lt;br&gt;
basis of my work is both rude and false. I'd be more than familiar with &lt;br&gt;
password shucking with or without it, which is why I can tell you what he &lt;br&gt;
meant there by suggesting a static key: &lt;em&gt;even&lt;/em&gt; a static key is good enough, &lt;br&gt;
&lt;em&gt;not&lt;/em&gt; only a static key. &lt;br&gt;
The salt being used that way adds more strength (which some would call &lt;br&gt;
overkill), not less. It being public has no effect on the purpose it serves &lt;br&gt;
either.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So what do we gain instead? Your RFC does not clearly state the &lt;br&gt;
benefits we gain at the cost of reduced security.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perhaps it was foolish of me to think that listing Bcrypt's well-known &lt;br&gt;
issues in the very first sentence of the RFC introduction is enough to &lt;br&gt;
suggest that they'd be fixed. Maybe I could be more explicit about it, and &lt;br&gt;
maybe you could not so aggressively strawman too. Just to be crystal clear: &lt;br&gt;
there is no reduced security.&lt;/p&gt;
&lt;p&gt;Cheers, &lt;br&gt;
Andrey.&lt;/p&gt;
</description><guid>CAPhkiZzteOhgLOzF+sVWpTOseaVYCsHoD9WOVb4cnDHvHBftxQ@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 23:29:14 +0000</pubDate></item><item><title>Request lifecycle hooks for SAPIs that serve multiple requests per script (like FrankenPHP in worker mode)</title><link>https://externals.io/message/132969</link><description>&lt;p&gt;Hi David,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Doesn't PHP with ZTS (Zend Thread Safety) offers the same capabilities?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, it's a different thing. ZTS gives each thread its own copy of the &lt;br&gt;
engine and extension globals, so several threads can run requests in &lt;br&gt;
parallel in the same process. But in both models, RINIT and RSHUTDOWN &lt;br&gt;
run once per script execution.&lt;/p&gt;
&lt;p&gt;In worker mode, a thread runs one script that handles many requests in &lt;br&gt;
a loop, so RINIT and RSHUTDOWN only run when that script starts and &lt;br&gt;
ends. ZTS doesn't change that.  By the way, FrankenPHP always uses &lt;br&gt;
ZTS, because it's written in Go, and Go relies heavily on threads &lt;br&gt;
(goroutines rely on system threads under the hood).&lt;/p&gt;
&lt;p&gt;Best&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello Kévin,&lt;/p&gt;
&lt;p&gt;I have a question. Doesn't PHP with ZTS (Zend Thread Safety) offers the same capabilities?&lt;/p&gt;
&lt;p&gt;I remember I read something about it. What you described reminded me of it. Although as I'm not an expert in the area I can't tell.&lt;/p&gt;
&lt;p&gt;The following link is from the PHP internal book for PHP lifecycle. (Although it says php7, I understand that it works the same for PHP8). &lt;br&gt;
&lt;a href="https://www.phpinternalsbook.com/php7/extensions_design/php_lifecycle.html" rel="nofollow" target="_blank"&gt;https://www.phpinternalsbook.com/php7/extensions_design/php_lifecycle.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I sent a screenshot of the page in attachment.&lt;/p&gt;
&lt;p&gt;I'm curious if this has to do with the question.&lt;/p&gt;
&lt;p&gt;Kind regards, &lt;br&gt;
David Maye&lt;/p&gt;
&lt;p&gt;Hello internals,&lt;/p&gt;
&lt;p&gt;As you may know, FrankenPHP and some other SAPIs (like the &lt;br&gt;
experimental ones written in Rust) have optional support for a &amp;quot;worker &lt;br&gt;
mode&amp;quot;. The main idea behind these worker modes is to use long-running &lt;br&gt;
scripts, started when the web server starts, to handle multiple HTTP &lt;br&gt;
requests in a loop.&lt;/p&gt;
&lt;p&gt;This allows keeping states in memory across requests - such as the &lt;br&gt;
Composer autoloader or Symfony and Laravel services - instead of &lt;br&gt;
re-computing them at the beginning of each new request. This also &lt;br&gt;
allows maintaining persistent connections to remote services across &lt;br&gt;
requests.&lt;/p&gt;
&lt;p&gt;Worker mode dramatically improves performance, at the cost of no &lt;br&gt;
longer isolating state between requests and losing the memory leak &lt;br&gt;
tolerance provided by the traditional &amp;quot;fire and forget&amp;quot; model. This &lt;br&gt;
mode has become increasingly popular since the release of FrankenPHP, &lt;br&gt;
and is now natively supported by a large part of the ecosystem &lt;br&gt;
(Symfony, Laravel, Yii...).&lt;/p&gt;
&lt;p&gt;Currently, the engine and extensions have no knowledge of this, and &lt;br&gt;
have no way to detect when a &amp;quot;real&amp;quot; HTTP request starts or ends. As &lt;br&gt;
expected, they are only aware of the start (and end) of the main, &lt;br&gt;
long-running script. FrankenPHP (and other SAPIs with a similar mode) &lt;br&gt;
reset &amp;quot;real HTTP request&amp;quot; related data by poking into the engine and &lt;br&gt;
first-party extensions &lt;br&gt;
(&lt;a href="https://github.com/php/frankenphp/blob/7f50be9d86261bf7cff9b051ab4fb572e95020ed/frankenphp.c#L400-L646" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/blob/7f50be9d86261bf7cff9b051ab4fb572e95020ed/frankenphp.c#L400-L646&lt;/a&gt;). &lt;br&gt;
This approach is fragile, and the internal code resetting these states &lt;br&gt;
can change without warning in a new PHP version.&lt;/p&gt;
&lt;p&gt;Each omission results in a cross-request leak or a memory safety bug. &lt;br&gt;
FrankenPHP fixed several of them this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a session ID leaking to other clients when ext/session is a shared &lt;br&gt;
module, because FrankenPHP can only reset the session globals when it &lt;br&gt;
is built against the session headers: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-v3ph-cgqh-r8p5" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-v3ph-cgqh-r8p5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a use-after-free of &lt;a href="php://temp" rel="nofollow" target="_blank"&gt;php://temp&lt;/a&gt; streams, because nothing releases &lt;br&gt;
SG(request_info).request_body between worker requests and FrankenPHP's &lt;br&gt;
own cleanup freed streams it didn't own: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-cm3q-jw2q-9rh5" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-cm3q-jw2q-9rh5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a double free because sapi_deactivate() frees &lt;br&gt;
SG(request_info).content_type_dup and current_user without clearing &lt;br&gt;
them (fixed for PHP 8.6: &lt;a href="https://github.com/php/php-src/pull/22974" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/22974&lt;/a&gt;): &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-h764-4wh7-m7j2" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-h764-4wh7-m7j2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http_get_last_response_headers()&lt;/code&gt; returning headers fetched by a &lt;br&gt;
previous request: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-pmvg-8483-mw84" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-pmvg-8483-mw84&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxml_get_errors()&lt;/code&gt; returning errors of a previous request, with &lt;br&gt;
parse-error fragments and server paths: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-4gfw-9v29-gp9h" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-4gfw-9v29-gp9h&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Third-party extensions detect the boundaries themselves, each in its &lt;br&gt;
own way. Xdebug and the Datadog profiler replace sapi_module.activate &lt;br&gt;
and sapi_module.deactivate when the SAPI is FrankenPHP. Datadog's &lt;br&gt;
tracer and AppSec, and New Relic in an open pull request, hook &lt;br&gt;
frankenphp_handle_request(). Blackfire's Symfony bridge, Tideways and &lt;br&gt;
Sentry wrap each request with start and stop calls in userland.&lt;/p&gt;
&lt;p&gt;Calling RSHUTDOWN and RINIT between worker requests doesn't work: &lt;br&gt;
these handlers mix state that needs resetting with state the script &lt;br&gt;
keeps. For instance, the standard extension's RSHUTDOWN releases the &lt;br&gt;
&lt;code&gt;strtok()&lt;/code&gt; state, but also destroys &lt;code&gt;register_tick_function()&lt;/code&gt; callbacks &lt;br&gt;
and user stream filters. The session extension's RSHUTDOWN writes and &lt;br&gt;
closes the session, but also frees the save handlers registered at &lt;br&gt;
boot. The libxml extension's RSHUTDOWN drops the external entity &lt;br&gt;
loader. Only each extension's maintainers know which of their globals &lt;br&gt;
belong to which kind.&lt;/p&gt;
&lt;p&gt;I'd like to add two optional module hooks, called by the SAPI between &lt;br&gt;
two logical requests of the same script:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;request_end: release the state tied to the finished request, but &lt;br&gt;
keep everything still reachable from userland;&lt;/li&gt;
&lt;li&gt;request_begin: set up the next request once its headers and &lt;br&gt;
superglobals are available (&lt;a href="http://session.auto" rel="nofollow" target="_blank"&gt;session.auto&lt;/a&gt;_start, Xdebug's triggers).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two engine functions, php_request_end() and php_request_begin(), would &lt;br&gt;
run the output and SAPI steps that worker SAPIs copy today from &lt;br&gt;
php_request_shutdown() and php_request_startup(), import the &lt;br&gt;
superglobals of the new request (except $_ENV, which comes from the &lt;br&gt;
process), set the execution timer, and call the hooks.&lt;/p&gt;
&lt;p&gt;Releasing the request body takes two small changes: &lt;a href="php://input" rel="nofollow" target="_blank"&gt;php://input&lt;/a&gt; &lt;br&gt;
streams hold a reference to the body, and freeing the body, for &lt;br&gt;
instance when the script closes it, clears &lt;br&gt;
SG(request_info).request_body. Core extensions would implement the &lt;br&gt;
hooks first; third-party extensions could adopt them at their pace. &lt;br&gt;
SAPIs that don't call these functions see no behavior change.&lt;/p&gt;
&lt;p&gt;I drafted a working patch for master, with the standard and session &lt;br&gt;
hooks: &lt;a href="https://github.com/dunglas/php-src/tree/request-boundary-hooks" rel="nofollow" target="_blank"&gt;https://github.com/dunglas/php-src/tree/request-boundary-hooks&lt;/a&gt;. &lt;br&gt;
FrankenPHP doesn't build against master yet, so I tested it with a &lt;br&gt;
patched version of FrankenPHP and it works.&lt;/p&gt;
&lt;p&gt;As this is an internal API with no userland or BC impact, an RFC isn't &lt;br&gt;
strictly needed.&lt;/p&gt;
&lt;p&gt;I made a similar but broader proposal almost 3 years ago &lt;br&gt;
(&lt;a href="https://externals.io/message/122027" rel="nofollow" target="_blank"&gt;https://externals.io/message/122027&lt;/a&gt;). I think time has shown that &lt;br&gt;
worker modes are here to stay, and this less intrusive proposal could &lt;br&gt;
fix several maintenance issues affecting the whole ecosystem.&lt;/p&gt;
&lt;p&gt;So, I would like your opinion on this before working more on it.&lt;/p&gt;
&lt;h2&gt;Best,&lt;/h2&gt;
&lt;p&gt;Kévin Dunglas&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dunglas.dev" rel="nofollow" target="_blank"&gt;https://dunglas.dev&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CADU7aotaZduR1ukjNDZfFvZx9J8fCpjJ6Ni_A4msuK4WPgKt-w@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 22:53:03 +0000</pubDate></item><item><title>Request lifecycle hooks for SAPIs that serve multiple requests per script (like FrankenPHP in worker mode)</title><link>https://externals.io/message/132968</link><description>&lt;p&gt;Hello Pierre,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;but shouldn't the need be covered by the Scope RFC &lt;a href="https://wiki.php.net/rfc/scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not really, they solve different problems.&lt;/p&gt;
&lt;p&gt;The Scope RFC gives an identity to requests running concurrently in &lt;br&gt;
the same process. It doesn't provide a point where a request ends: as &lt;br&gt;
the RFC says, a scope doesn't finish when run() returns. It also only &lt;br&gt;
covers the superglobals, the session, the default locale and the &lt;br&gt;
default timezone.&lt;/p&gt;
&lt;p&gt;My proposal is a small internal refactoring that adds two optional &lt;br&gt;
hooks, called between two requests served one after the other by the &lt;br&gt;
same script. They let each extension release its own request state, &lt;br&gt;
which today worker SAPIs reset by poking into the extensions' globals. &lt;br&gt;
The bugs we fixed in FrankenPHP were in state the Scope RFC doesn't &lt;br&gt;
cover: &lt;code&gt;strtok()&lt;/code&gt;, the last HTTP response headers, libxml errors, the &lt;br&gt;
request body.&lt;/p&gt;
&lt;p&gt;It's a quality of life improvement for the existing ecosystem (SAPIs &lt;br&gt;
with a worker mode and the extensions supporting them). Unlike the &lt;br&gt;
Scope RFC, it has no impact on userland code and requires no change to &lt;br&gt;
it. Worker modes are already widely used and will remain even if the &lt;br&gt;
Scope RFC passes, at least for backward compatibility.&lt;/p&gt;
&lt;p&gt;The two proposals are complementary. If both are accepted, the parts &lt;br&gt;
touching the superglobals and the session would need to work together, &lt;br&gt;
but nothing conflicts.&lt;/p&gt;
&lt;p&gt;Best&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le 29/10/2026 à 18:47, Kévin Dunglas a écrit :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello internals,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hello,&lt;/p&gt;
&lt;p&gt;I see the point and I feel it's indeed at some point becomes a &lt;br&gt;
requirement for long running servers, yet to be honest this not my area &lt;br&gt;
of expertise, but shouldn't the need be covered by the Scope RFC &lt;br&gt;
&lt;a href="https://wiki.php.net/rfc/scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt; ?&lt;/p&gt;
&lt;p&gt;The chosen path is different, but the goal seems to be the same in the end.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Pierre&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CADU7aotG1QbtvDRc-VRQiQ08Hqf+NKxJS=ABHCCVP5OjhJXTPA@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 22:52:40 +0000</pubDate></item><item><title>RFC karma request: grapheme_str_pad()</title><link>https://externals.io/message/132967</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to request RFC karma on the wiki to propose a new function, &lt;br&gt;
grapheme_str_pad(). My wiki username is: chrisabner&lt;/p&gt;
&lt;p&gt;It is the grapheme cluster counterpart of &lt;code&gt;str_pad()&lt;/code&gt; and &lt;code&gt;mb_str_pad()&lt;/code&gt;, as &lt;br&gt;
suggested in the Future Scope of the mb_str_pad RFC [1]. The length is &lt;br&gt;
counted in grapheme clusters, like &lt;code&gt;grapheme_strlen()&lt;/code&gt; does:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grapheme_str_pad(string $string, int $length, string $pad_string = &amp;quot; &amp;quot;,
                 int $pad_type = STR_PAD_RIGHT): string|false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mb_str_pad()&lt;/code&gt; counts code points, so the same visible text gets different &lt;br&gt;
padding depending on how it is encoded, and the padding string can be cut &lt;br&gt;
inside a grapheme cluster:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mb_str_pad(&amp;quot;Caf\u{00E9}&amp;quot;, 6, '.');           // &amp;quot;Café..&amp;quot;
mb_str_pad(&amp;quot;Cafe\u{0301}&amp;quot;, 6, '.');          // &amp;quot;Café.&amp;quot;  (NFD: one dot less)
mb_str_pad(&amp;quot;a&amp;quot;, 4, &amp;quot;u\u{0308}o\u{0308}&amp;quot;);    // &amp;quot;aüo&amp;quot;    (ö lost its diaeresis)

grapheme_str_pad(&amp;quot;Cafe\u{0301}&amp;quot;, 6, '.');       // &amp;quot;Café..&amp;quot;
grapheme_str_pad(&amp;quot;a&amp;quot;, 4, &amp;quot;u\u{0308}o\u{0308}&amp;quot;); // &amp;quot;aüöü&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Errors and edge cases follow &lt;code&gt;mb_str_pad()&lt;/code&gt;; invalid UTF-8 returns false like &lt;code&gt;grapheme_strlen()&lt;/code&gt;. I have an implementation with tests in ext/intl and will &lt;br&gt;
open a pull request together with the RFC.&lt;/p&gt;
&lt;p&gt;I'll open the formal [RFC] discussion thread once the wiki page is up.&lt;/p&gt;
&lt;p&gt;[1] &lt;a href="https://wiki.php.net/rfc/mb_str_pad#future_scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/mb_str_pad#future_scope&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Chris Abner Herrera Navarro&lt;/p&gt;
</description><guid>SA3PR12MB7877E15EAAB2B71C15B531BCD66E2@SA3PR12MB7877.namprd12.prod.outlook.com</guid><pubDate>Thu, 29 Oct 2026 22:00:35 +0000</pubDate></item><item><title>[Meta] This Week In PHP Internals | October 29, 2026</title><link>https://externals.io/message/132966</link><description>&lt;p&gt;Hi Contributors,&lt;/p&gt;
&lt;p&gt;This week's episode is out. Here's the video, plus everywhere else it landed &lt;br&gt;
for visibility.&lt;/p&gt;
&lt;p&gt;Same invitation as always: if I got something wrong, reply in this thread &lt;br&gt;
and &lt;br&gt;
I'll make corrections. That includes how I'm pronouncing your names.&lt;/p&gt;
&lt;p&gt;If you'd rather read than watch, the &lt;a href="http://dev.to" rel="nofollow" target="_blank"&gt;dev.to&lt;/a&gt; post carries the full episode as &lt;br&gt;
an article, which also makes it the easiest version to quote when correcting &lt;br&gt;
me: &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-oct-29-2026-1m75" rel="nofollow" target="_blank"&gt;https://dev.to/projektgopher/this-week-in-php-internals-oct-29-2026-1m75&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;youtube &lt;a href="https://youtu.be/oeDHs-qXXwA" rel="nofollow" target="_blank"&gt;https://youtu.be/oeDHs-qXXwA&lt;/a&gt; &lt;br&gt;
r/php &lt;br&gt;
&lt;a href="https://www.reddit.com/r/PHP/comments/1xix3qk/this_week_in_php_internals_oct_29_2026/" rel="nofollow" target="_blank"&gt;https://www.reddit.com/r/PHP/comments/1xix3qk/this_week_in_php_internals_oct_29_2026/&lt;/a&gt; &lt;br&gt;
r/symfony &lt;br&gt;
&lt;a href="https://www.reddit.com/r/symfony/comments/1xix6f5/this_week_in_php_internals_oct_29_2026/" rel="nofollow" target="_blank"&gt;https://www.reddit.com/r/symfony/comments/1xix6f5/this_week_in_php_internals_oct_29_2026/&lt;/a&gt; &lt;br&gt;
r/laravel &lt;br&gt;
&lt;a href="https://www.reddit.com/r/laravel/comments/1xix9qe/this_week_in_php_internals_oct_29_2026/" rel="nofollow" target="_blank"&gt;https://www.reddit.com/r/laravel/comments/1xix9qe/this_week_in_php_internals_oct_29_2026/&lt;/a&gt; &lt;br&gt;
&lt;a href="http://dev.to" rel="nofollow" target="_blank"&gt;dev.to&lt;/a&gt; &lt;br&gt;
&lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-oct-29-2026-1m75" rel="nofollow" target="_blank"&gt;https://dev.to/projektgopher/this-week-in-php-internals-oct-29-2026-1m75&lt;/a&gt; &lt;br&gt;
mastodon &lt;a href="https://phpc.social/@ProjektGopher/117526253139268972" rel="nofollow" target="_blank"&gt;https://phpc.social/@ProjektGopher/117526253139268972&lt;/a&gt; &lt;br&gt;
threads &lt;a href="https://www.threads.com/@projektgopher/post/DfF9VKxkl-6" rel="nofollow" target="_blank"&gt;https://www.threads.com/@projektgopher/post/DfF9VKxkl-6&lt;/a&gt; &lt;br&gt;
bsky &lt;a href="https://bsky.app/profile/projektgopher.com/post/3mz27x74cwy2w" rel="nofollow" target="_blank"&gt;https://bsky.app/profile/projektgopher.com/post/3mz27x74cwy2w&lt;/a&gt; &lt;br&gt;
twitter &lt;a href="https://x.com/ProjektGopher/status/2115915517009801479" rel="nofollow" target="_blank"&gt;https://x.com/ProjektGopher/status/2115915517009801479&lt;/a&gt; &lt;br&gt;
linkedin &lt;br&gt;
&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7521683881872371713/" rel="nofollow" target="_blank"&gt;https://www.linkedin.com/feed/update/urn:li:activity:7521683881872371713/&lt;/a&gt; &lt;br&gt;
pinkary &lt;br&gt;
&lt;a href="https://pinkary.com/@ProjektGopher/questions/01a1898e-f67e-72f1-a20f-7e074590a55c" rel="nofollow" target="_blank"&gt;https://pinkary.com/@ProjektGopher/questions/01a1898e-f67e-72f1-a20f-7e074590a55c&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cheers, &lt;br&gt;
Len&lt;/p&gt;
</description><guid>CAEwAiAE6dtAvcGnhFwZT_fb7G2RP88ZnXyD_Xh5kLrODoWUDpw@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 21:54:33 +0000</pubDate></item><item><title>[RFC][Discussion] Add PASSWORD_BCRYPT_WRAP</title><link>https://externals.io/message/132965</link><description>&lt;blockquote&gt;
&lt;p&gt;Hi all,&lt;/p&gt;
&lt;p&gt;I'd like to open the discussion on a new password hashing algorithm that I've been working on, named bcrypt-wrap.&lt;/p&gt;
&lt;p&gt;RFC link: &lt;a href="https://wiki.php.net/rfc/password_bcrypt_wrap" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/password_bcrypt_wrap&lt;/a&gt; &lt;br&gt;
Pull request: &lt;a href="https://github.com/php/php-src/pull/25040" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/25040&lt;/a&gt; (just pushed it, CI still running)&lt;/p&gt;
&lt;p&gt;P.S. Thanks to Sjoerd for honoring my request to delay his bcrypt-sha256 proposal while I finished this.&lt;/p&gt;
&lt;p&gt;Cheers, &lt;br&gt;
Andrey.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hi Andrey,&lt;/p&gt;
&lt;p&gt;I'm rather against it. Your proposed implementation decreases security &lt;br&gt;
of bcrypt implementation for small and dubious gains. The input space &lt;br&gt;
is decreased from 2^576 to 2^432, which is a magnitude of 2^144. Sure, &lt;br&gt;
these are astronomical values, but it's a significant decrease &lt;br&gt;
nonetheless.&lt;/p&gt;
&lt;p&gt;Additionally, your implementation suffers from hash shucking. OWASP &lt;br&gt;
explicitly warns about doing it the way you are doing it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Just using pure SHA-512, ( i.e. bcrypt(base64(sha512($password))), $salt, $cost)) is a dangerous practice and is as secure as just using pure SHA-512. &lt;br&gt;
&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html" rel="nofollow" target="_blank"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You mention HMAC, but it's a bit vague and looking at the &lt;br&gt;
implementation, I believe you use the public salt as a secret key. &lt;br&gt;
This may obfuscate the hash, but as I understand it, it does not make &lt;br&gt;
pre-hashing safe. In fact the blog which I assume you have looked at &lt;br&gt;
before (&lt;a href="https://soatok.blog/2024/11/27/beyond-bcrypt/" rel="nofollow" target="_blank"&gt;https://soatok.blog/2024/11/27/beyond-bcrypt/&lt;/a&gt;) describes the &lt;br&gt;
problems in detail:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can avoid hash shucking by using HMAC with a static key–either universal for all deployments of your software, or unique per application.&lt;/p&gt;
&lt;p&gt;It doesn’t really matter which you choose; all you really need from it is domain separation from naked hashes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So what do we gain instead? Your RFC does not clearly state the &lt;br&gt;
benefits we gain at the cost of reduced security.&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Kamil Tekiela&lt;/p&gt;
</description><guid>CAGBsUrfJ0pehZ85-7VykJj7Ow+ksOZOa6=tDdKWiiHPg4ENdLA@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 21:39:47 +0000</pubDate></item><item><title>[RFC] openssl_get_channel_binding</title><link>https://externals.io/message/132964</link><description>&lt;p&gt;Thank you for the thorough review.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have created an RFC to add the function openssl_get_channel_binding: &lt;br&gt;
&lt;a href="https://wiki.php.net/rfc/openssl_get_channel_binding" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/openssl_get_channel_binding&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;“The function returns null when the requested type is not applicable &lt;br&gt;
to the connection.”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;An operation that is not applicable sounds like an Exception to me. Is &lt;br&gt;
there currently any other situation where &lt;code&gt;null&lt;/code&gt; is returned?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No. I can see the appeal of throwing a specific exception (e.g. UnsupportedChannelBinding extends OpensslExtension). Then if the function returns something the caller knows it is a valid channel binding value.&lt;/p&gt;
&lt;p&gt;The RFC already identifies the case for tls-unique over TLS 1.3. I think using tls-server-end-point over TLS-PSK also may not work (because there's no certificate) and should also throw such an exception.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="2"&gt;
&lt;li&gt;“$stream is a stream, but it has no active OpenSSL TLS transport”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That sounds like a programmer error, thus &lt;code&gt;Openssl\OpensslError&lt;/code&gt; (or &lt;br&gt;
potentially ValueError).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, I agree.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="3"&gt;
&lt;li&gt;“An OpenSSL call fails while computing the value”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Is this one reachable in practice or is this more of a generic “catch &lt;br&gt;
all” error that cannot really happen?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This was meant as a generic catch all for things that should not normally fail.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="4"&gt;
&lt;li&gt;“Because the second parameter is an enum, the function itself no &lt;br&gt;
longer has an unknown-type error. […]”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This paragraph should probably not be mentioned in the RFC&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, I agree. I removed this.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="7"&gt;
&lt;li&gt;RFC Impact to “To Existing Extensions”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Are there perhaps any extensions that might want to make use of the new &lt;br&gt;
functionality internally? For example pdo_pgsql, I'm noting that the RFC &lt;br&gt;
mentions tests against PostgreSQL?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I hadn't considered this. Not really. Most extensions don't use a connection managed by ext/openssl. E.g. for postgres, libpq does the TLS handling and also the channel binding. Mysqlnd does use a PHP stream, but MySQL/mariadb don't have any channel binding functionality.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>913d6d60-e5bf-4e49-b9e6-02a46ce5e0cd@app.fastmail.com</guid><pubDate>Thu, 29 Oct 2026 20:18:51 +0000</pubDate></item><item><title>[RFC][Discussion] Add PASSWORD_BCRYPT_WRAP</title><link>https://externals.io/message/132963</link><description>&lt;p&gt;Hi all,&lt;/p&gt;
&lt;p&gt;I'd like to open the discussion on a new password hashing algorithm that &lt;br&gt;
I've been working on, named bcrypt-wrap.&lt;/p&gt;
&lt;p&gt;RFC link: &lt;a href="https://wiki.php.net/rfc/password_bcrypt_wrap" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/password_bcrypt_wrap&lt;/a&gt; &lt;br&gt;
Pull request: &lt;a href="https://github.com/php/php-src/pull/25040" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/25040&lt;/a&gt; (just pushed it, CI &lt;br&gt;
still running)&lt;/p&gt;
&lt;p&gt;P.S. Thanks to Sjoerd for honoring my request to delay his bcrypt-sha256 &lt;br&gt;
proposal while I finished this.&lt;/p&gt;
&lt;p&gt;Cheers, &lt;br&gt;
Andrey.&lt;/p&gt;
</description><guid>CAPhkiZyaENhbAZXtnhb7c220_2sPBPR9LKdOajyXm-1JpfwNPA@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 20:06:42 +0000</pubDate></item><item><title>Request lifecycle hooks for SAPIs that serve multiple requests per script (like FrankenPHP in worker mode)</title><link>https://externals.io/message/132962</link><description></description><guid>0a5ebd9c-b21f-4860-afd2-4d85997c4bec@email.android.com</guid><pubDate>Thu, 29 Oct 2026 18:20:51 +0000</pubDate></item><item><title>Request lifecycle hooks for SAPIs that serve multiple requests per script (like FrankenPHP in worker mode)</title><link>https://externals.io/message/132961</link><description>&lt;p&gt;Le 29/10/2026 à 18:47, Kévin Dunglas a écrit :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello internals,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hello,&lt;/p&gt;
&lt;p&gt;I see the point and I feel it's indeed at some point becomes a &lt;br&gt;
requirement for long running servers, yet to be honest this not my area &lt;br&gt;
of expertise, but shouldn't the need be covered by the Scope RFC &lt;br&gt;
&lt;a href="https://wiki.php.net/rfc/scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt; ?&lt;/p&gt;
&lt;p&gt;The chosen path is different, but the goal seems to be the same in the end.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Pierre&lt;/p&gt;
</description><guid>f1b37f50-0725-47ad-add2-a05cec358efe@processus.org</guid><pubDate>Thu, 29 Oct 2026 18:01:57 +0000</pubDate></item><item><title>Request lifecycle hooks for SAPIs that serve multiple requests per script (like FrankenPHP in worker mode)</title><link>https://externals.io/message/132960</link><description>&lt;p&gt;Hello internals,&lt;/p&gt;
&lt;p&gt;As you may know, FrankenPHP and some other SAPIs (like the &lt;br&gt;
experimental ones written in Rust) have optional support for a &amp;quot;worker &lt;br&gt;
mode&amp;quot;. The main idea behind these worker modes is to use long-running &lt;br&gt;
scripts, started when the web server starts, to handle multiple HTTP &lt;br&gt;
requests in a loop.&lt;/p&gt;
&lt;p&gt;This allows keeping states in memory across requests - such as the &lt;br&gt;
Composer autoloader or Symfony and Laravel services - instead of &lt;br&gt;
re-computing them at the beginning of each new request. This also &lt;br&gt;
allows maintaining persistent connections to remote services across &lt;br&gt;
requests.&lt;/p&gt;
&lt;p&gt;Worker mode dramatically improves performance, at the cost of no &lt;br&gt;
longer isolating state between requests and losing the memory leak &lt;br&gt;
tolerance provided by the traditional &amp;quot;fire and forget&amp;quot; model. This &lt;br&gt;
mode has become increasingly popular since the release of FrankenPHP, &lt;br&gt;
and is now natively supported by a large part of the ecosystem &lt;br&gt;
(Symfony, Laravel, Yii...).&lt;/p&gt;
&lt;p&gt;Currently, the engine and extensions have no knowledge of this, and &lt;br&gt;
have no way to detect when a &amp;quot;real&amp;quot; HTTP request starts or ends. As &lt;br&gt;
expected, they are only aware of the start (and end) of the main, &lt;br&gt;
long-running script. FrankenPHP (and other SAPIs with a similar mode) &lt;br&gt;
reset &amp;quot;real HTTP request&amp;quot; related data by poking into the engine and &lt;br&gt;
first-party extensions &lt;br&gt;
(&lt;a href="https://github.com/php/frankenphp/blob/7f50be9d86261bf7cff9b051ab4fb572e95020ed/frankenphp.c#L400-L646" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/blob/7f50be9d86261bf7cff9b051ab4fb572e95020ed/frankenphp.c#L400-L646&lt;/a&gt;). &lt;br&gt;
This approach is fragile, and the internal code resetting these states &lt;br&gt;
can change without warning in a new PHP version.&lt;/p&gt;
&lt;p&gt;Each omission results in a cross-request leak or a memory safety bug. &lt;br&gt;
FrankenPHP fixed several of them this year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a session ID leaking to other clients when ext/session is a shared &lt;br&gt;
module, because FrankenPHP can only reset the session globals when it &lt;br&gt;
is built against the session headers: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-v3ph-cgqh-r8p5" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-v3ph-cgqh-r8p5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a use-after-free of &lt;a href="php://temp" rel="nofollow" target="_blank"&gt;php://temp&lt;/a&gt; streams, because nothing releases &lt;br&gt;
SG(request_info).request_body between worker requests and FrankenPHP's &lt;br&gt;
own cleanup freed streams it didn't own: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-cm3q-jw2q-9rh5" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-cm3q-jw2q-9rh5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;a double free because sapi_deactivate() frees &lt;br&gt;
SG(request_info).content_type_dup and current_user without clearing &lt;br&gt;
them (fixed for PHP 8.6: &lt;a href="https://github.com/php/php-src/pull/22974" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/22974&lt;/a&gt;): &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-h764-4wh7-m7j2" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-h764-4wh7-m7j2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;http_get_last_response_headers()&lt;/code&gt; returning headers fetched by a &lt;br&gt;
previous request: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-pmvg-8483-mw84" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-pmvg-8483-mw84&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;libxml_get_errors()&lt;/code&gt; returning errors of a previous request, with &lt;br&gt;
parse-error fragments and server paths: &lt;br&gt;
&lt;a href="https://github.com/php/frankenphp/security/advisories/GHSA-4gfw-9v29-gp9h" rel="nofollow" target="_blank"&gt;https://github.com/php/frankenphp/security/advisories/GHSA-4gfw-9v29-gp9h&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Third-party extensions detect the boundaries themselves, each in its &lt;br&gt;
own way. Xdebug and the Datadog profiler replace sapi_module.activate &lt;br&gt;
and sapi_module.deactivate when the SAPI is FrankenPHP. Datadog's &lt;br&gt;
tracer and AppSec, and New Relic in an open pull request, hook &lt;br&gt;
frankenphp_handle_request(). Blackfire's Symfony bridge, Tideways and &lt;br&gt;
Sentry wrap each request with start and stop calls in userland.&lt;/p&gt;
&lt;p&gt;Calling RSHUTDOWN and RINIT between worker requests doesn't work: &lt;br&gt;
these handlers mix state that needs resetting with state the script &lt;br&gt;
keeps. For instance, the standard extension's RSHUTDOWN releases the &lt;br&gt;
&lt;code&gt;strtok()&lt;/code&gt; state, but also destroys &lt;code&gt;register_tick_function()&lt;/code&gt; callbacks &lt;br&gt;
and user stream filters. The session extension's RSHUTDOWN writes and &lt;br&gt;
closes the session, but also frees the save handlers registered at &lt;br&gt;
boot. The libxml extension's RSHUTDOWN drops the external entity &lt;br&gt;
loader. Only each extension's maintainers know which of their globals &lt;br&gt;
belong to which kind.&lt;/p&gt;
&lt;p&gt;I'd like to add two optional module hooks, called by the SAPI between &lt;br&gt;
two logical requests of the same script:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;request_end: release the state tied to the finished request, but &lt;br&gt;
keep everything still reachable from userland;&lt;/li&gt;
&lt;li&gt;request_begin: set up the next request once its headers and &lt;br&gt;
superglobals are available (&lt;a href="http://session.auto" rel="nofollow" target="_blank"&gt;session.auto&lt;/a&gt;_start, Xdebug's triggers).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two engine functions, php_request_end() and php_request_begin(), would &lt;br&gt;
run the output and SAPI steps that worker SAPIs copy today from &lt;br&gt;
php_request_shutdown() and php_request_startup(), import the &lt;br&gt;
superglobals of the new request (except $_ENV, which comes from the &lt;br&gt;
process), set the execution timer, and call the hooks.&lt;/p&gt;
&lt;p&gt;Releasing the request body takes two small changes: &lt;a href="php://input" rel="nofollow" target="_blank"&gt;php://input&lt;/a&gt; &lt;br&gt;
streams hold a reference to the body, and freeing the body, for &lt;br&gt;
instance when the script closes it, clears &lt;br&gt;
SG(request_info).request_body. Core extensions would implement the &lt;br&gt;
hooks first; third-party extensions could adopt them at their pace. &lt;br&gt;
SAPIs that don't call these functions see no behavior change.&lt;/p&gt;
&lt;p&gt;I drafted a working patch for master, with the standard and session &lt;br&gt;
hooks: &lt;a href="https://github.com/dunglas/php-src/tree/request-boundary-hooks" rel="nofollow" target="_blank"&gt;https://github.com/dunglas/php-src/tree/request-boundary-hooks&lt;/a&gt;. &lt;br&gt;
FrankenPHP doesn't build against master yet, so I tested it with a &lt;br&gt;
patched version of FrankenPHP and it works.&lt;/p&gt;
&lt;p&gt;As this is an internal API with no userland or BC impact, an RFC isn't &lt;br&gt;
strictly needed.&lt;/p&gt;
&lt;p&gt;I made a similar but broader proposal almost 3 years ago &lt;br&gt;
(&lt;a href="https://externals.io/message/122027" rel="nofollow" target="_blank"&gt;https://externals.io/message/122027&lt;/a&gt;). I think time has shown that &lt;br&gt;
worker modes are here to stay, and this less intrusive proposal could &lt;br&gt;
fix several maintenance issues affecting the whole ecosystem.&lt;/p&gt;
&lt;p&gt;So, I would like your opinion on this before working more on it.&lt;/p&gt;
&lt;h2&gt;Best,&lt;/h2&gt;
&lt;p&gt;Kévin Dunglas&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dunglas.dev" rel="nofollow" target="_blank"&gt;https://dunglas.dev&lt;/a&gt;&lt;/p&gt;
</description><guid>CADU7aovTpg1kq-sbeD0=a4buSDD2L8s+zGPrd53+y5TOk=e2og@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 17:47:58 +0000</pubDate></item><item><title>[RFC] CSV Extension (ext/csv)</title><link>https://externals.io/message/132959</link><description>&lt;blockquote&gt;
&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does it mean that the LazyLaxCollection will expose the stream metadata &lt;br&gt;
? &lt;br&gt;
If I receive in my method/function a  LazyLaxCollection is it possible &lt;br&gt;
for &lt;br&gt;
me to get access to the underlying resource metadata ? To know how it &lt;br&gt;
is &lt;br&gt;
open, its pathname , and so forth ? Can I easily detect if&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That paragraph appears to be cut off. Can you check?&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Indeed it was cut off I rephrased it as follow:&lt;/p&gt;
&lt;p&gt;Does this mean that &lt;code&gt;LazyLaxCollection&lt;/code&gt; will expose the stream metadata?&lt;/p&gt;
&lt;p&gt;If I receive a &lt;code&gt;LazyLaxCollection&lt;/code&gt; instance in a method or function, will I &lt;br&gt;
be able to access the underlying resource metadata:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;understand how the stream was opened,&lt;/li&gt;
&lt;li&gt;retrieve its pathname, and ... ?&lt;/li&gt;
&lt;li&gt;can I easily determine whether the underlying stream is a local file, &lt;br&gt;
a temporary file, a memory stream, or something else?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are genuine questions that someone might ask when working with an &lt;br&gt;
instantiated &lt;code&gt;LazyLaxCollection&lt;/code&gt; object.&lt;/p&gt;
</description><guid>CAOV5rgbXqratvEbspHCr9gcdmoBagh+F=u0x5ja-A0uXNywhaw@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 16:27:01 +0000</pubDate></item><item><title>[RFC] CSV Extension (ext/csv)</title><link>https://externals.io/message/132958</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Does it mean that the LazyLaxCollection will expose the stream metadata &lt;br&gt;
? &lt;br&gt;
If I receive in my method/function a  LazyLaxCollection is it possible &lt;br&gt;
for &lt;br&gt;
me to get access to the underlying resource metadata ? To know how it &lt;br&gt;
is &lt;br&gt;
open, its pathname , and so forth ? Can I easily detect if&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That paragraph appears to be cut off. Can you check?&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>9f86cd4266e4aac51e047497e4b90328@bastelstu.be</guid><pubDate>Thu, 29 Oct 2026 16:16:11 +0000</pubDate></item><item><title>[RFC] CSV Extension (ext/csv)</title><link>https://externals.io/message/132957</link><description>&lt;p&gt;On Fri, Oct 9, 2026 at 8:22 AM Damian Jóźwiak &lt;a href="mailto:damian.jozwiak.lodz@gmail.com"&gt;damian.jozwiak.lodz@gmail.com&lt;/a&gt; &lt;br&gt;
wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to open the discussion on an RFC proposing a dedicated CSV &lt;br&gt;
extension (ext/csv) for PHP core.&lt;/p&gt;
&lt;p&gt;RFC: &lt;a href="https://wiki.php.net/rfc/csv_extension" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/csv_extension&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Implementation: &lt;a href="https://github.com/php/php-src/pull/24199" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24199&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The proposal builds upon Gina Peter Banyard's girgias/csv extension &lt;br&gt;
(BSD-3-Clause), with additional functionality for file and stream handling.&lt;/p&gt;
&lt;p&gt;The motivation includes the deprecation of the SplFileObject CSV methods &lt;br&gt;
in PHP 8.6, which leaves certain use cases without a direct replacement.&lt;/p&gt;
&lt;p&gt;The proposed extension provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Six functions and one class in the Csv\ namespace.&lt;/h2&gt;
&lt;h2&gt;RFC 4180-compatible parsing and serialization by default.&lt;/h2&gt;
&lt;h2&gt;Locale-independent processing without the proprietary escape mechanism.&lt;/h2&gt;
&lt;h2&gt;Multibyte delimiters, enclosures, and EOL sequences.&lt;/h2&gt;
&lt;h2&gt;Strict and lax collection parsing.&lt;/h2&gt;
&lt;p&gt;Lazy iteration over CSV files and streaming output.&lt;/p&gt;
&lt;p&gt;The implementation includes PHPT tests covering parsing, serialization, &lt;br&gt;
stream handling, resource lifetime, and various edge cases.&lt;/p&gt;
&lt;p&gt;The pull request's CI checks are currently passing across the tested &lt;br&gt;
platforms, including debug, ZTS, and AddressSanitizer configurations.&lt;/p&gt;
&lt;p&gt;The initial API is deliberately kept small. A more comprehensive &lt;br&gt;
object-oriented Reader/Writer API, including capability-oriented &lt;br&gt;
interfaces, is left for potential future discussion.&lt;/p&gt;
&lt;p&gt;I'd particularly appreciate feedback on the public API design, the naming &lt;br&gt;
of LazyLaxCollection, and whether the extension should be always enabled &lt;br&gt;
or optional at build time.&lt;/p&gt;
&lt;p&gt;For transparency, Gina has not reviewed or endorsed this RFC. Parts of the &lt;br&gt;
implementation were developed with LLM assistance; I have reviewed the code &lt;br&gt;
and take full responsibility for the contribution.&lt;/p&gt;
&lt;p&gt;This is an invitation for discussion, not a call for votes.&lt;/p&gt;
&lt;p&gt;Thanks in advance for your feedback.&lt;/p&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Damian Jóźwiak&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hi Damien, &lt;br&gt;
thanks for the proposal, indeed with the deprecation of SplFileObject CSV &lt;br&gt;
feature an object oriented alternative is welcomed having said that.I have &lt;br&gt;
a couple of remarks/suggestions&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Following Tim's thought, I wonder if a CSV top namespace is mandatory &lt;br&gt;
or if we should not just have a Serialization &amp;quot;namespace&amp;quot; name that can be &lt;br&gt;
improved when such classes and functions are defined.&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;*RFC 4180-compatible parsing and serialization by default. *As much as I &lt;br&gt;
am a proponent of backing RFC whenever they exist in this case it should be &lt;br&gt;
stressed out that RFC4180 is not an accepted RFC like for instance RFC3986 &lt;br&gt;
for URI specification as such it is totally possible to have a valid CSV &lt;br&gt;
which does not comply with the refer draft specification. I believe this &lt;br&gt;
should be noted and explained in the RFC to avoid pushing forward something &lt;br&gt;
which is not a real specification as anyone would expect even though it is &lt;br&gt;
widely accepted as the &amp;quot;default&amp;quot; implementation,&lt;/h2&gt;
&lt;h2&gt;Hence why I believe that using terms like &lt;em&gt;lax&lt;/em&gt; and &lt;em&gt;strict&lt;/em&gt; is counter &lt;br&gt;
productive; probably other names &amp;quot;to be defined&amp;quot; should be used instead. &lt;br&gt;
Maybe adding an Enum With RFC4180 and something else (?) would be a better &lt;br&gt;
take. Which would reduce the number of function/methods introduced ?&lt;/h2&gt;
&lt;p&gt;Also while it is common to talk about CSV, this feature would be &lt;br&gt;
perhaps better called &lt;em&gt;Character Separated Value&lt;/em&gt; than  Comma Separated &lt;br&gt;
Value since the delimiter can be changed. And covers TSV and other exotic &lt;br&gt;
formats which separates values per single character.&lt;/p&gt;
&lt;p&gt;The stream is owned by the object: like the stream of SplFileObject, it&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;remains visible as a resource but &lt;code&gt;fclose()&lt;/code&gt; refuses to close it, and it is &lt;br&gt;
closed when the object is destroyed (for an object alive until the end of &lt;br&gt;
the request, while destructors run, so a user wrapper's stream_close() is &lt;br&gt;
still called).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Does it mean that the LazyLaxCollection will expose the stream metadata ? &lt;br&gt;
If I receive in my method/function a  LazyLaxCollection is it possible for &lt;br&gt;
me to get access to the underlying resource metadata ? To know how it is &lt;br&gt;
open, its pathname , and so forth ? Can I easily detect if&lt;/p&gt;
&lt;p&gt;Being able to configure the context or to apply stream filter is also &lt;br&gt;
something I find useful with the current set of csv function even with &lt;br&gt;
SplFileObject (even though it is tricky with that one) I would expect any &lt;br&gt;
API which aim at replacing the current CSV API to offer at most the same &lt;br&gt;
extensibility or to allow it in any other shape or form.&lt;/p&gt;
&lt;p&gt;function collection_to_file(string $file, iterable $collection, string &lt;br&gt;
$delimiter = ',', string $enclosure = '&amp;quot;', string $eolSequence = &lt;br&gt;
&amp;quot;\r\n&amp;quot;): void {}&lt;/p&gt;
&lt;p&gt;Why? can't we have access to the written bytes as returned value. Otherwise &lt;br&gt;
it means we need to re-access the resource afterward if we want to get &lt;br&gt;
access to that value. For example if we want to generate the Content-Length &lt;br&gt;
header or something else ?&lt;/p&gt;
&lt;p&gt;Overall, I like the direction of the RFC but I believe some major &lt;br&gt;
discussion points remain unsolved before going to a vote&lt;/p&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Ignace&lt;/p&gt;
</description><guid>CAOV5rgb7gjo4EwTA0Zs63whMy1_fRt8Gt1t34SRqzECyM9CcEg@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 15:33:42 +0000</pubDate></item><item><title>PHP 8.4.27 configure writes to read-only source tree but exits successfully</title><link>https://externals.io/message/132956</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I found a reproducible out-of-tree build-system issue in the signed PHP &lt;br&gt;
8.4.27 release. I am using the internals list because &lt;a href="http://bugs.php.net" rel="nofollow" target="_blank"&gt;bugs.php.net&lt;/a&gt; no &lt;br&gt;
longer accepts reports and GitHub is unavailable in this environment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thank you for your report. A PR was filed by Pratik in response to your &lt;br&gt;
email: &lt;a href="https://github.com/php/php-src/pull/24597" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24597&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>a2bd7985cd1c7aa800ef37b6aa028136@bastelstu.be</guid><pubDate>Thu, 29 Oct 2026 15:05:57 +0000</pubDate></item><item><title>SSRF protection in curl</title><link>https://externals.io/message/132955</link><description>&lt;p&gt;Hi Levi,&lt;/p&gt;
&lt;p&gt;Good point, with one caveat. I think we might apply the same logic to &lt;br&gt;
streams, but as the decision must be made per-request, the implementation &lt;br&gt;
should be specific per api. &lt;br&gt;
So I'd rather focus on curl here and make sure it lands in 8.7, then we &lt;br&gt;
might open another rfc for streams.&lt;/p&gt;
&lt;p&gt;WDYT ?&lt;/p&gt;
&lt;p&gt;Le jeu. 22 oct. 2026 à 16:58, Levi Morrison &lt;a href="mailto:levi.morrison@datadoghq.com"&gt;levi.morrison@datadoghq.com&lt;/a&gt; a &lt;br&gt;
écrit :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there any reason we should intentionally make this curl specific? &lt;br&gt;
Meaning, we could design support for making it work for streams as &lt;br&gt;
well, couldn't we? Why make a curl specific feature instead of a &lt;br&gt;
language wide one?&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CAKNL=Fd97rg6zmdFShxNdSHq26VZg50hBAxGsFKYcORDwQg_yg@mail.gmail.com</guid><pubDate>Thu, 29 Oct 2026 14:05:49 +0000</pubDate></item><item><title>[RFC] Time\Instant and Time\Clock</title><link>https://externals.io/message/132954</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;ol start="7"&gt;
&lt;li&gt;get vs to&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I agree with this.  $foo-&amp;gt;toBar() is a very common &amp;quot;type conversion&amp;quot; &lt;br&gt;
pattern, and it makes sense to use here as well.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Already adjusted a while ago.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;ol start="8"&gt;
&lt;li&gt;getUnixTimestamp() / getUnixTimestampMilliseconds()&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I would agree here as well.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;See the reply I just sent to Marc.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;ol start="13"&gt;
&lt;li&gt;A dedicated parser/formatter instead&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I'd prefer parsing and formatting to live in a dedicated &lt;br&gt;
parser/formatter &lt;br&gt;
API (future scope) rather than on Instant, where it would sit next to &lt;br&gt;
the &lt;br&gt;
other ISO-8601 profiles and custom patterns. If the pair stays on &lt;br&gt;
Instant, &lt;br&gt;
the name should say what it really is (a fixed RFC 3339-like profile), &lt;br&gt;
and &lt;br&gt;
the grammar should be part of what we vote on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I understand the tidiness/purity argument here, and I am generally &lt;br&gt;
sympathetic to it.  However, that always needs to be balanced against &lt;br&gt;
usability.  Any incoming date/time information to the PHP process is &lt;br&gt;
likely to be either an ISO-8601 string or a unix timestamp int.  If we &lt;br&gt;
want people to convert those into Instants for doing manipulation and &lt;br&gt;
comparison on (which I presume is the case), then that needs to be &lt;br&gt;
ergonomically easy to do.  Having to go through multiple &lt;br&gt;
parser/converter objects (which some purist is likely to insist be &lt;br&gt;
injected from a container rather than instantiated directly; I have &lt;br&gt;
been known to be that purist) to get there is not ergonomic.  So if &lt;br&gt;
that logic is split off, we would need to be very careful to ensure the &lt;br&gt;
result is ergonomically simple and readily copy-pasteable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, I've expanded a little more in my own words in the reply I just &lt;br&gt;
sent to Marc.&lt;/p&gt;
&lt;p&gt;Regarding the “purist note”: Injecting a formatter (into your template &lt;br&gt;
engine) actually is reasonable. The correct choice there would likely be &lt;br&gt;
one backed by ext/intl.&lt;/p&gt;
&lt;p&gt;And of course, as I had noted in &lt;br&gt;
&lt;a href="https://news-web.php.net/php.internals/132608" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132608&lt;/a&gt; and the reply to Marc, &lt;br&gt;
arbitrary formatting is only well-defined for a &lt;code&gt;ZonedDateTime&lt;/code&gt; (or &lt;br&gt;
&lt;code&gt;PlainDateTime&lt;/code&gt; - naming tbd - when the timezone is implied). For &lt;br&gt;
&lt;code&gt;Instant&lt;/code&gt; we can just use anything that unambiguously represents a point &lt;br&gt;
in time, which basically boils down to ISO-8601 date time with zone &lt;br&gt;
offset. Users are able to build their own parsers if they have a &lt;br&gt;
requirement for special formats. Or parse into &lt;code&gt;ZonedDateTime&lt;/code&gt; and &lt;br&gt;
extract the instant via &lt;code&gt;ZonedDateTime::$instant&lt;/code&gt; (or whatever it may be &lt;br&gt;
called).&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;ol start="14"&gt;
&lt;li&gt;until() vs Duration::between()&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Was Duration::between(Instant $a, Instant $b) considered? Calculating &lt;br&gt;
a &lt;br&gt;
duration feels like Duration's responsibility to me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This also seems reasonable, as a named constructor of Duration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;See the reply I just sent to Marc.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>d5e73b759488f82e6f25b61707a0dc5a@bastelstu.be</guid><pubDate>Thu, 29 Oct 2026 13:57:00 +0000</pubDate></item><item><title>[RFC] Time\Instant and Time\Clock</title><link>https://externals.io/message/132953</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;Due to the security releases it's been a while since I last looked into &lt;br&gt;
this RFC and I probably lost some of my working memory. Please indicate &lt;br&gt;
if there is something obvious that I missed somewhere or similar.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Naming of Clock::now()&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The method returns an Instant, but the RFC already plans future classes &lt;br&gt;
that combine an instant with a timezone (a ZonedDateTime-like class). &lt;br&gt;
Callers &lt;br&gt;
will want to get those from a clock directly as well, without going the &lt;br&gt;
long way around: $clock-&amp;gt;now()-&amp;gt;toZonedDateTime($zone). Once a clock &lt;br&gt;
can return more than one type, &lt;code&gt;now()&lt;/code&gt; no longer says what you get.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A “point in time” is the canonical representation of “now” for the &lt;br&gt;
reasons that are also given in the RFC and this is also the type I &lt;br&gt;
expect to be returned, even without including it in the name. As you &lt;br&gt;
note yourself, a &lt;code&gt;ZonedDateTime&lt;/code&gt; requires supplementary information (the &lt;br&gt;
timezone) to be provided at call time. For that I would also not call it &lt;br&gt;
“going the long way around”. As a direct comparison:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; $clock-&amp;gt;now()-&amp;gt;toZonedDateTime($zone)
 // vs your suggested
 $clock-&amp;gt;takeZonedDateTime($zone)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;saves a grand total of 5 characters, at the expense of making the “point &lt;br&gt;
in time” retrieval much more verbose. The &lt;code&gt;ZonedDateTime&lt;/code&gt; will very &lt;br&gt;
likely be a thin wrapper over &lt;code&gt;Instant&lt;/code&gt; + &lt;code&gt;Timezone&lt;/code&gt;, thus the &lt;code&gt;Instant&lt;/code&gt; &lt;br&gt;
object can just be reused as &lt;code&gt;ZonedDateTime::$instant&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I would also say that using a &lt;code&gt;ZonedDateTime&lt;/code&gt; as the default type for &lt;br&gt;
handling time is doing it wrong. The timezone is a presentation-layer &lt;br&gt;
concern and stuff you “present” to the user is generally expected to be &lt;br&gt;
coming from the database, rather than coming from the clock. Allowing &lt;br&gt;
comparisons between &lt;code&gt;ZonedDateTime&lt;/code&gt; and “now” can be enabled by just &lt;br&gt;
making &lt;code&gt;ZonedDateTime::compare()&lt;/code&gt; accept &lt;code&gt;Instant|ZonedDateTime&lt;/code&gt; as the &lt;br&gt;
parameters. The nice part of the &lt;code&gt;compare()&lt;/code&gt; method is that it's &lt;br&gt;
specifically designed for ordering rather than equality, thus a return &lt;br&gt;
value of &lt;code&gt;0&lt;/code&gt; can mean “same point in time” even if the timezones differ.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One constraint thought, PHP interfaces can't have default &lt;br&gt;
implementations. Adding methods to Time\Clock later would break every &lt;br&gt;
userland clock. So either the interface should get its full shape now, &lt;br&gt;
or further result types should come in through factories on the target &lt;br&gt;
types &lt;br&gt;
(see 2).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, adding methods to interfaces after the fact is a breaking change &lt;br&gt;
and “huge interfaces” are an indicator of wrong design. Java solves this &lt;br&gt;
by making the Clock an abstract class, but this also is a heavy-weight &lt;br&gt;
solution to something that is not really a problem as per the above, so &lt;br&gt;
…&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Instant::fromClock(Clock $clock)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You rejected Instant::now() because it would tie Instant to the &lt;br&gt;
SystemClock. With a required Clock parameter that objection goes away. &lt;br&gt;
It is exactly what Java does. Later classes can then follow the same &lt;br&gt;
pattern &lt;br&gt;
(ZonedDateTime::fromClock($clock, $zone)) without the Clock interface &lt;br&gt;
ever &lt;br&gt;
growing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;… that would be a reasonable middle-ground of providing convenience &lt;br&gt;
constructors. With the &lt;code&gt;from*()&lt;/code&gt; prefix the naming is consistent and it &lt;br&gt;
doesn't magically invent information out of thin air. Given that it's &lt;br&gt;
pretty much redundant with &lt;code&gt;$clock-&amp;gt;now()&lt;/code&gt; with the current scope of the &lt;br&gt;
RFC, I would punt this to when &lt;code&gt;ZonedDateTime&lt;/code&gt; is introduced so that it &lt;br&gt;
can be designed consistently across all classes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Clock resolution&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The docblock says &amp;quot;at the resolution offered by the underlying clock&amp;quot;, &lt;br&gt;
but &lt;br&gt;
nothing in the API exposes that resolution (Rob raised the same point). &lt;br&gt;
I &lt;br&gt;
measured what the platforms report via clock_getres() and what they &lt;br&gt;
actually deliver:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As I noted in my reply to Rob, I don't believe this is something that &lt;br&gt;
belongs on the interface, since this information is unlikely to be &lt;br&gt;
actionable by a majority of applications …&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;code&gt;                         clock_getres()   smallest observed step
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;macOS arm64, REALTIME      1 us             1 us &lt;br&gt;
Linux arm64, REALTIME      1 ns             42 ns (24 MHz counter) &lt;br&gt;
Linux, REALTIME_COARSE     1 ms             -&lt;/p&gt;
&lt;p&gt;So clock_getres() is honest on some systems and only nominal on others. &lt;br&gt;
I'd still like SystemClock to expose it, documented as the nominal &lt;br&gt;
resolution of the source. That is better than no information at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;… but we can see how exposing the (nominal) resolution of specifically &lt;br&gt;
the SystemClock can be useful. I assume that a &lt;br&gt;
&lt;code&gt;SystemClock::getNominalResolution(): Duration&lt;/code&gt; with the &lt;code&gt;Duration&lt;/code&gt; &lt;br&gt;
being the greatest common divisor of possible returned values is what &lt;br&gt;
you would expect? I have just added a future scope note to the RFC, &lt;br&gt;
since I would need to do additional research into all the operating &lt;br&gt;
systems supported by PHP. It's probably also something that can just go &lt;br&gt;
in by “simple PR” without going through a full RFC, since this is a &lt;br&gt;
minor feature on a &lt;code&gt;final&lt;/code&gt; class.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Configurable clock resolution&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Handled previously.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Taking a Unix timestamp directly from a clock&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Unix timestamps are used everywhere, not only in PHP, so &amp;quot;current time &lt;br&gt;
as a Unix timestamp&amp;quot; is a very common operation. Today that's &lt;code&gt;time()&lt;/code&gt;, &lt;br&gt;
which can't be mocked. With this RFC the mockable replacement is &lt;br&gt;
$clock-&amp;gt;now()-&amp;gt;getUnixTimestamp(), which always goes through an Instant &lt;br&gt;
object. I'd like a way to take the Unix timestamp directly from the &lt;br&gt;
clock.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Our goal with this RFC series is to provide a well-designed and &lt;br&gt;
well-typed new API that nudges the user to do the right thing. Making &lt;br&gt;
“raw integers” a first class citizen would go against that goal to save &lt;br&gt;
7 characters (and one object creation). The previous arguments against &lt;br&gt;
adding a &lt;code&gt;takeZonedDateTime()&lt;/code&gt; or similar also apply here.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="6"&gt;
&lt;li&gt;&amp;quot;Follows POSIX time&amp;quot; vs. &amp;quot;unspecified representation&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The RFC states that Instants &amp;quot;follow POSIX time&amp;quot;. At the same time it &lt;br&gt;
says &lt;br&gt;
that &amp;quot;the internal representation of Time\Instant is intentionally left &lt;br&gt;
unspecified and there are deliberately no public properties. In &lt;br&gt;
particular &lt;br&gt;
the 'Unix timestamp' is not the primary representation.&amp;quot;&lt;/p&gt;
&lt;p&gt;I think an unspecified internal representation is the right way &lt;br&gt;
forward. But it doesn't match the class being specified as POSIX time. &lt;br&gt;
POSIX time is not just one of many ways to look at an instant. It is a &lt;br&gt;
specific time &lt;br&gt;
scale: seconds counted since 1970-01-01T00:00:00Z. If Instant follows &lt;br&gt;
POSIX time, then the Unix timestamp (plus a fraction of a second) is &lt;br&gt;
effectively the model of the class.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's not quite seconds counted since 1970-01-01T00:00:00Z, the relevant &lt;br&gt;
part is that leap seconds are dropped (which makes the POSIX timescale &lt;br&gt;
different from UTC).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So I'd suggest not defining Instant itself in terms of POSIX time. &lt;br&gt;
POSIX &lt;br&gt;
time is relevant where Unix timestamps come in or go out, so it belongs &lt;br&gt;
in &lt;br&gt;
the documentation of the Unix timestamp constructor and getter, not in &lt;br&gt;
the &lt;br&gt;
definition of the class.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'll look into cleaning up the wording when handling the points that Rob &lt;br&gt;
mentioned.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="7"&gt;
&lt;li&gt;get vs to&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Handled previously.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="8"&gt;
&lt;li&gt;getUnixTimestamp() / getUnixTimestampMilliseconds()&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Only the milliseconds variant names its unit, and microseconds (used &lt;br&gt;
all &lt;br&gt;
over PHP: &lt;code&gt;microtime()&lt;/code&gt;, DateTime) and nanoseconds are missing entirely. &lt;br&gt;
A &lt;br&gt;
single pair taking the unit as an argument would cover all of them and &lt;br&gt;
stay symmetric:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;toUnixTimestamp()&lt;/code&gt; + &lt;code&gt;getNanoseconds()&lt;/code&gt; pair is the canonical &lt;br&gt;
representation of a Unix timestamp - with “seconds” also being arguably &lt;br&gt;
by far the most common interpretation when hearing “Unix timestamp”. The &lt;br&gt;
“milliseconds” variant is provided for interoperability convenience, in &lt;br&gt;
particular with JavaScript.&lt;/p&gt;
&lt;p&gt;PHP’s existing &lt;code&gt;DateTime&lt;/code&gt; does not provide functionality to obtain the &lt;br&gt;
timestamp as an integral number of microseconds, and &lt;code&gt;microtime()&lt;/code&gt; &lt;br&gt;
either returns a &lt;code&gt;float&lt;/code&gt; or a weird two-component pair as a string. I am &lt;br&gt;
not aware of anything commonly used that returns “integral microseconds &lt;br&gt;
since the Unix epoch”, do you know of anything?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;public static function fromUnixTimestamp(int $timestamp, TimeUnit &lt;br&gt;
$unit = TimeUnit::Second): self; &lt;br&gt;
public function toUnixTimestamp(TimeUnit $unit = TimeUnit::Second): &lt;br&gt;
int;&lt;/p&gt;
&lt;p&gt;TimeUnit would be an enum of Second, Millisecond, Microsecond and &lt;br&gt;
Nanosecond, rounding towards negative infinity as already specified. &lt;br&gt;
The&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I do not find it obvious at all that “seconds” would be the largest &lt;br&gt;
supported unit of a &lt;code&gt;TimeUnit&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="9"&gt;
&lt;li&gt;getNanoseconds()&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Handled previously.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="10"&gt;
&lt;li&gt;Concepts the ISO-8601 pair brings into Instant&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;An Instant is described as a timezone-less point in time. The ISO-8601 &lt;br&gt;
constructor and getter bring in several concepts that Instant otherwise &lt;br&gt;
deliberately avoids:&lt;/p&gt;
&lt;p&gt;a) parsing and formatting of date-time strings; &lt;br&gt;
b) UTC as the reference (&amp;quot;Z&amp;quot; means a zero offset from UTC; since RFC &lt;br&gt;
9557 it formally means &amp;quot;UTC known, local offset unknown&amp;quot;); &lt;br&gt;
c) a calendar: ISO 8601 uses the proleptic Gregorian calendar with &lt;br&gt;
year &lt;br&gt;
0000; &lt;br&gt;
d) an opinionated input and output format&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes. I don't understand what you are getting at, though. There clearly &lt;br&gt;
has to be a way to represent a point in time in some way - and an &lt;br&gt;
ISO-8601 datetime string is one of the possible options, probably the &lt;br&gt;
most widely used one. The Unix timestamp is another one.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="11"&gt;
&lt;li&gt;The accepted input grammar&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The RFC says the parser is strict but &amp;quot;may not support all legal &lt;br&gt;
formats&amp;quot;, &lt;br&gt;
and that accepted formats can be extended &amp;quot;by a simple pull request&amp;quot;. &lt;br&gt;
That &lt;br&gt;
means the vote doesn't decide the accepted grammar. Widening it later &lt;br&gt;
is &lt;br&gt;
also not BC-neutral for code that uses the parser as a validator. I'd &lt;br&gt;
like&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since the RFC guarantees that only legal formats will be accepted, you &lt;br&gt;
are able to use it as a validator. If your use case requires narrower &lt;br&gt;
validation, then you will need to perform custom validation according to &lt;br&gt;
whatever specification you are dealing with. This is not unique to the &lt;br&gt;
Instant class.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the RFC to specify the grammar explicitly and to state the outcome for &lt;br&gt;
the &lt;br&gt;
cases Ilia listed: comma decimal sign, lowercase t/z, space separator, &lt;br&gt;
-00:00, 24:00:00, 23:59:60, more than 9 fractional digits.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;See my reply to Ilia (&lt;a href="https://news-web.php.net/php.internals/132764" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132764&lt;/a&gt;). &lt;br&gt;
The RFC changes are still open.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A related point: &lt;br&gt;
the docblock requires &amp;quot;a zone offset&amp;quot; while the prose requires &amp;quot;a &lt;br&gt;
timezone&amp;quot;. Is an RFC 9557 suffix such as [Europe/Berlin] accepted, &lt;br&gt;
rejected or ignored?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks, I adjusted the prose to also require a “zone offset”.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="12"&gt;
&lt;li&gt;The output format&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The getter always emits Z, has a fractional part whose width depends on &lt;br&gt;
the value (omitted when zero, otherwise 9 digits), and uses signed &lt;br&gt;
expanded years outside 0000-9999.&lt;/p&gt;
&lt;p&gt;You mentioned that the getter implements the RFC 3339 subset of &lt;br&gt;
ISO-8601. &lt;br&gt;
That is not quite true: RFC 3339 only allows 4-digit years 0000-9999, &lt;br&gt;
so the output isn't RFC 3339 for expanded years.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is a bit of a distinction without difference: RFC 3339 is only &lt;br&gt;
capable of representing years 0000 to 9999, so years outside of that &lt;br&gt;
range are by definition not representable as RFC 3339. The ISO-8601 &lt;br&gt;
getter specifically only switches to the expanded format outside that &lt;br&gt;
range. Adding a separate RFC 3339 getter that differs only by throwing &lt;br&gt;
an Exception for unrepresentable instants does not sound useful, since &lt;br&gt;
this Exception is not actionable in any way.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I also tested how well the possible outputs work as input for the &lt;br&gt;
existing &lt;br&gt;
DateTime API (PHP 8.5):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;new DateTimeImmutable($s) accepts all of them, but truncates the 9 &lt;br&gt;
fractional digits to 6 without notice.&lt;/li&gt;
&lt;li&gt;With createFromFormat() no single format string works. &lt;code&gt;DATE_ATOM&lt;/code&gt; &lt;br&gt;
only &lt;br&gt;
matches whole seconds with 4-digit years. DATE_RFC3339_EXTENDED &lt;br&gt;
(.v, &lt;br&gt;
3 digits) never matches. 'Y-m-d\TH:i:s.uP' fails on 9 digits &lt;br&gt;
because &lt;br&gt;
'u' takes at most 6, so you need a hack like 'Y-m-d\TH:i:s.u???P'. &lt;br&gt;
Expanded years need 'X' instead of 'Y'.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because the fractional part is only present for some values, any strict &lt;br&gt;
consumer needs at least two format strings and has to choose between &lt;br&gt;
them, &lt;br&gt;
which is the trap Ilia described. An output that always includes the &lt;br&gt;
fractional part would at least make 'X-m-d\TH:i:s.u???P' work for every &lt;br&gt;
value.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I do not believe that the existing &lt;code&gt;DateTime&lt;/code&gt; API is a model of good &lt;br&gt;
design in that regard (and there are better ways for interoperability &lt;br&gt;
with it, as noted in &lt;a href="https://news-web.php.net/php.internals/132761" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132761&lt;/a&gt;). &lt;br&gt;
Only taking a fixed format is already a problem as of now, because &lt;br&gt;
“conditionally omitting the fractional part” is common.&lt;/p&gt;
&lt;p&gt;The specified format is interoperable with JavaScript's &lt;br&gt;
&lt;code&gt;Temporal.Instant.from()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; &amp;gt; Temporal.Instant.from('1969-07-20T20:17:40Z')
 Temporal.Instant 1969-07-20T20:17:40Z

 &amp;gt; Temporal.Instant.from('1969-07-20T20:17:40.123456789Z')
 Temporal.Instant 1969-07-20T20:17:40.123456789Z

 &amp;gt; Temporal.Instant.from('1969-07-20T20:17:40.123000000Z')
 Temporal.Instant 1969-07-20T20:17:40.123Z
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Go’s time.RFC3339Nano:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; t, err := time.Parse(time.RFC3339Nano, &amp;quot;1969-07-20T20:17:40Z&amp;quot;)
 fmt.Printf(&amp;quot;%+v\n&amp;quot;, t) // 1969-07-20 20:17:40 +0000 UTC
 fmt.Printf(&amp;quot;%+v\n&amp;quot;, err) // &amp;lt;nil&amp;gt;
 t, err = time.Parse(time.RFC3339Nano, 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;quot;1969-07-20T20:17:40.123456789Z&amp;quot;) &lt;br&gt;
fmt.Printf(&amp;quot;%+v\n&amp;quot;, t) // 1969-07-20 20:17:40.123456789 +0000 UTC &lt;br&gt;
fmt.Printf(&amp;quot;%+v\n&amp;quot;, err) // &amp;lt;nil&amp;gt; &lt;br&gt;
t, err = time.Parse(time.RFC3339Nano, &lt;br&gt;
&amp;quot;1969-07-20T20:17:40.123000000Z&amp;quot;) &lt;br&gt;
fmt.Printf(&amp;quot;%+v\n&amp;quot;, t) // 1969-07-20 20:17:40.123 +0000 UTC &lt;br&gt;
fmt.Printf(&amp;quot;%+v\n&amp;quot;, err) // &amp;lt;nil&amp;gt;&lt;/p&gt;
&lt;p&gt;With Java’s &lt;code&gt;java.time.Instant.parse()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; System.out.println(Instant.parse(&amp;quot;1969-07-20T20:17:40Z&amp;quot;)); // 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;1969-07-20T20:17:40Z &lt;br&gt;
System.out.println(Instant.parse(&amp;quot;1969-07-20T20:17:40.123456789Z&amp;quot;)); &lt;br&gt;
// 1969-07-20T20:17:40.123456789Z &lt;br&gt;
System.out.println(Instant.parse(&amp;quot;1969-07-20T20:17:40.123000000Z&amp;quot;)); &lt;br&gt;
// 1969-07-20T20:17:40.123Z&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="13"&gt;
&lt;li&gt;A dedicated parser/formatter instead&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I'd prefer parsing and formatting to live in a dedicated &lt;br&gt;
parser/formatter &lt;br&gt;
API (future scope) rather than on Instant, where it would sit next to &lt;br&gt;
the &lt;br&gt;
other ISO-8601 profiles and custom patterns. If the pair stays on &lt;br&gt;
Instant, &lt;br&gt;
the name should say what it really is (a fixed RFC 3339-like profile), &lt;br&gt;
and &lt;br&gt;
the grammar should be part of what we vote on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I agree with Larry’s DX argument here. I'd also like to note that the &lt;br&gt;
&lt;em&gt;output&lt;/em&gt; format is fixed by the RFC. The input format is less &lt;br&gt;
constrained, but the RFC guarantees that it stays true to its name by &lt;br&gt;
only accepting what ISO-8601 specifies.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="14"&gt;
&lt;li&gt;until() vs Duration::between()&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Was Duration::between(Instant $a, Instant $b) considered? Calculating a &lt;br&gt;
duration feels like Duration's responsibility to me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That suggestion breaks down when measuring elapsed time with a monotonic &lt;br&gt;
clock. PHP does not support method overloading, so it would need to &lt;br&gt;
become &lt;code&gt;Duration::between(Instant|MonoInstant, Instant|MonoInstant)&lt;/code&gt; &lt;br&gt;
which then also allows non-sense combinations.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="15"&gt;
&lt;li&gt;Smaller things&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;On 32-bit, Duration only covers about 68 years, so until() is more &lt;br&gt;
limited there than the examples suggest. That's worth a sentence.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Added a note to &lt;code&gt;until()&lt;/code&gt;’s docblock.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Duration uses sign-magnitude for its (seconds, nanoseconds) pair, &lt;br&gt;
while fromUnixTimestamp(-1, 500_000_000) uses floor semantics (-0.5s). &lt;br&gt;
Both are defensible, but the RFC should say why they differ.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, the Unix timestamp needs “floor semantics” due to external &lt;br&gt;
constraints: The second part only ticks once the full second has &lt;br&gt;
elapsed. Negative Unix timestamps are also comparatively rare and not &lt;br&gt;
always well-defined (e.g. POSIX does not specify a negative &lt;code&gt;time_t&lt;/code&gt;). &lt;br&gt;
This is different for Duration where negative values can regularly &lt;br&gt;
appear and where direct interaction with the properties is the expected &lt;br&gt;
use case.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>5d35cad3b7192a90a77ce31c49f5b8aa@bastelstu.be</guid><pubDate>Thu, 29 Oct 2026 13:39:14 +0000</pubDate></item><item><title>[RFC] Scope</title><link>https://externals.io/message/132952</link><description>&lt;blockquote&gt;
&lt;p&gt;The examples will avoid the PFA form, though, because it reads like a call, &lt;br&gt;
and the difference between running code in the scope and running it before &lt;br&gt;
the scope is entered is three dots:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$scope-&amp;gt;run(doAThing(1, 2, 4, ...)); // doAThing runs in $scope
$scope-&amp;gt;run(doAThing(1, 2, 4));      // doAThing runs in the caller's scope;
                                     // run() gets whatever it returned
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'd request at least one example somewhere that shows using the PFA form, if only to clarify that it's legal and valid.  (Whether it's optimally readable is a more subjective question I'm fine not addressing here.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;A scope keeps no link to the scope it was run from.&amp;quot; So that fully &lt;br&gt;
precludes getParentScope() and such, yes? What is the reason?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's simple to add in userspace with a WeakMap&amp;lt;Scope, Scope&amp;gt;, for code that &lt;br&gt;
wants a hierarchy. In core it would carry a risk of memory leaks: an app &lt;br&gt;
designed to create each new scope from the previous one, millions of times, &lt;br&gt;
would keep the whole chain alive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's valid.  Please include that in the RFC.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;I think you mean &amp;quot;PHP process&amp;quot; here&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Under the CLI the root scope is the process, yes. Under php-fpm it is the &lt;br&gt;
request, not the process, which handles many requests. I'll spell out both &lt;br&gt;
cases instead of saying &amp;quot;request&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, the terminology here is going to be tricky, but important to be extremely clear on.  &amp;quot;request&amp;quot; already means a half dozen things today depending on context, so maybe it's best to avoid it where possible in the RFC?&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Am I correct in summarizing it as &amp;quot;a closure inherits the scope of its &lt;br&gt;
callsite, not creation site&amp;quot;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes. Closures don't have a scope; stack frames do. A closure is just code: &lt;br&gt;
while it runs, some scope is current, and later the same closure can run &lt;br&gt;
while another scope is current. What matters is the scope that called it, &lt;br&gt;
since the scope never changes while a function's instructions are running.&lt;/p&gt;
&lt;p&gt;Fibers and generators look different, but follow the same rule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A fiber gets a scope because it will get a stack frame as soon as &lt;br&gt;
$fiber-&amp;gt;start() is called. It is bound to the scope that created it, so &lt;br&gt;
it starts in that scope, whoever starts or resumes it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A generator function is just a function and isn't bound to a scope. But &lt;br&gt;
a Generator is, in a sense, a stack frame: calling the function creates &lt;br&gt;
it, so the Generator object (not the generator function) is bound to the &lt;br&gt;
scope it was created in.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'll add examples for each.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ah, so a rule of &amp;quot;scope is bound at stack-frame-creation-time&amp;quot; is a useful global rule to state explicitly, then explain how it applies to various scenarios.  That would help clarify the logic, methinks.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;For secondary vote A (the superglobals), the example is very unclear. &lt;br&gt;
[...] Forget to do so and poof&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;$request and $handler are the server's own; I'll make that explicit. The &lt;br&gt;
copying is not something applications do. It is done once, by whatever &lt;br&gt;
creates the request scope: Swerve, FrankenPHP, RoadRunner. That is the same &lt;br&gt;
place that fills the superglobals today.&lt;/p&gt;
&lt;p&gt;A new scope starting with empty superglobals is deliberate. Scopes are a &lt;br&gt;
new feature, and it seems safer to start the scope's globals empty and &lt;br&gt;
require frameworks to populate them, than to start them as clones of the &lt;br&gt;
parent's. Clones would let a parent scope mutate values inside its child &lt;br&gt;
scopes through object properties, and every framework would have to clear &lt;br&gt;
them out first.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm not clear how the parent scope could mutate values inside the new scope.&lt;/p&gt;
&lt;p&gt;My concern is this sort of case:&lt;/p&gt;
&lt;p&gt;function legacyLogic(string $message) &lt;br&gt;
{ &lt;br&gt;
print $message . ', ' . $_GET['name']; &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;If that is run today, it works.  (It's dumb, but it works.)&lt;/p&gt;
&lt;p&gt;However, if we do this:&lt;/p&gt;
&lt;p&gt;new Scope()-&amp;gt;run(legacyLogic('Hello', ...));&lt;/p&gt;
&lt;p&gt;Then inside the scope $_GET['name'] no longer exists, so poof, it no longer works.  And in a non-trivial scenario, legacyLogic() could be called 20 functions deep, so it's nearly impossible to know that it exists. It means as the scope creator I need to always do something like this, just in case:&lt;/p&gt;
&lt;p&gt;$get = $_GET; &lt;br&gt;
$post = $_POST; &lt;br&gt;
$request = $_REQUEST; &lt;br&gt;
$server = $_SERVER; &lt;br&gt;
new Scope()-&amp;gt;run(function () use($get, $post, $request, $server) { &lt;br&gt;
$_GET = $get; &lt;br&gt;
$_POST = $post; &lt;br&gt;
$_REQUEST = $request; &lt;br&gt;
$_SERVER = $server; &lt;br&gt;
legacyLogic('hello'); &lt;br&gt;
});&lt;/p&gt;
&lt;p&gt;Needing to write lots of boilerplate like that &amp;quot;just in case&amp;quot; is a red flag in my mind.  Moreover, if the secondary vote doesn't pass initially but is introduced in some later version, it becomes a BC break for anything using a superglobal that happens to be called from within a scope, something the function (by design) doesn't know.&lt;/p&gt;
&lt;p&gt;Not cloning feels like a footgun.  I would think initializing with a clone of the parent scope and letting the scope setup code modify it if desired would be the safer option, and require less work.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The first mention of $GLOBALS is in the superglobal secondary vote &lt;br&gt;
section. [...] I am undecided if I agree globals should not follow the &lt;br&gt;
scope.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'll move that up. Globals and static properties stay shared because &lt;br&gt;
applications use them for caches, registries and singletons. Warming those &lt;br&gt;
once and keeping them across requests is the reason to run in worker mode &lt;br&gt;
at all. If they followed the scope, every request would start cold.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's a valid argument, but both are also frequently used for request-specific caches today.  (Global current user, or a static cache that derives from request-sensitive data, etc.)  Those would suddenly become buggy if there's multiple scopes happening and the code isn't prepared for it.&lt;/p&gt;
&lt;p&gt;Thought: Would a &lt;code&gt;scoped&lt;/code&gt; keyword on a static property or global (maybe just static property) be useful, to easily separate that data by scope rather than needing to reengineer it to use a WeakMap?  Basically automating the WeakMap logic.&lt;/p&gt;
&lt;p&gt;I suppose that wouldn't help with BC anymore than telling people to use getCurrent() would, but it's something.  BC would require doing it via an attribute, and I don't know if there's appetite for that.&lt;/p&gt;
&lt;p&gt;Something like:&lt;/p&gt;
&lt;p&gt;class Foo { &lt;br&gt;
#[Scoped] &lt;br&gt;
private static $cache;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public function getFoos() {
    return $this-&amp;gt;cache ??= $this-&amp;gt;computeFoosRequestSensitive();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Which simply automates the WeakMap logic that everyone would need to replicate anyway, while also being backward compatible with existing code.&lt;/p&gt;
&lt;p&gt;Other thought: We already have a magic syntax for &amp;quot;the current object scope&amp;quot;: $this.  Would it make sense to have some other first-class syntax for Scope::getCurrent() that is more compact and self-descriptive?  $scope almost certainly wouldn't work for BC reasons, but maybe a keyword?&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;However, I am still uneasy about how narrow it is. [...] I also fear that &lt;br&gt;
the result is we'll have a lot of subtly-different and incompatible ways &lt;br&gt;
of handling that&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is what we have today, and it's why I wrote this. I spent two years &lt;br&gt;
trying to do it in userspace with phasync. phasync attaches a context to &lt;br&gt;
each fiber and that context follows every child fiber. It almost works, &lt;br&gt;
but not quite:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm sold on the use case, and the more I think about it the more sold I am.  It's more that I'm torn on this point:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Scope could store values, but then it could quickly become a kind of &lt;br&gt;
service locator and encourage poor design. A WeakMap keyed on Scope &lt;br&gt;
avoids naming conventions for keys, and it limits who can reach &lt;br&gt;
something like a database connection: only the code holding the map.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;which is a concern I completely share!  I don't think $scope-&amp;gt;attributes['good luck keeping these straight'] is the right answer either.  My concern is if everyone needs to write their own WeakMap routines, it is very likely that at least a third of them will be subtly wrong in some way.  The #[Scoped] attribute above might go a long way to mitigating that concern, but it requires some more consideration.&lt;/p&gt;
&lt;p&gt;Also, if we just &amp;quot;magically&amp;quot; separate the superglobals or locale or timezone or whatever, it's not obvious that something has been separated.  As the list of things that are separated grows with future RFCs, that could introduce subtle behavior breaks that only show up when code is used in a scope, as in the $_GET example above.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="6"&gt;
&lt;li&gt;There will be bugs, but not necessarily subtle ones. When one process &lt;br&gt;
handles 5000 concurrent requests, you can't hand out 5000 PDO &lt;br&gt;
connections; you need a limit on the total and a pool. Scope doesn't &lt;br&gt;
cause that class of bug. High concurrency does, and the community will &lt;br&gt;
have to learn to work with it, as Java, C#, Node and Python did.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's going to be fun to deal with...  Are there good examples we can point to to help PHP collectively wrap its head around that pattern faster?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In none of these do classes look services up through the request &lt;br&gt;
identity: they still get their dependencies through the constructor. PHP &lt;br&gt;
has no such identity today, and that is all the primary vote adds.&lt;/p&gt;
&lt;p&gt;This is a complete PSR-11 container with the three lifetimes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;final class Container implements Psr\Container\ContainerInterface
{
    private array $shared = [];
    private WeakMap $scoped;   // Scope =&amp;gt; that scope's services

    /** @param array&amp;lt;string, array{Closure(self): mixed, 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;'singleton'|'scoped'|'transient'}&amp;gt; $services */ &lt;br&gt;
public function __construct(private array $services) &lt;br&gt;
{ &lt;br&gt;
$this-&amp;gt;scoped = new WeakMap(); &lt;br&gt;
}&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    public function get(string $id): mixed
    {
        [$make, $lifetime] = $this-&amp;gt;services[$id] ?? throw new 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NotFound($id);&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        if ('scoped' === $lifetime) {
            $mine = $this-&amp;gt;scoped[Scope::getCurrent()] ??= new 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ArrayObject();&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;            return $mine[$id] ??= $make($this);
        }

        return 'singleton' === $lifetime ? $this-&amp;gt;shared[$id] ??= 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;$make($this) : $make($this); &lt;br&gt;
}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the sort of code I fear everyone doing slightly differently and half of us getting it slightly wrong.&lt;/p&gt;
&lt;p&gt;If I understand correctly, it would also then be incumbent on the container to ensure that a service that depends on a scoped service is itself scoped.  If it doesn't, that sounds like Weird Things(tm) could happen.  (As in my database example below.)&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;code&gt;    public function has(string $id): bool
    {
        return isset($this-&amp;gt;services[$id]);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A singleton is built once per worker, a scoped service once per request, &lt;br&gt;
and the request's services are freed with its scope, without the container &lt;br&gt;
ever hearing that the request ended.&lt;/p&gt;
&lt;p&gt;For your case, your services stay singletons and are built once per &lt;br&gt;
worker. Only the connection is resolved per request, which is what &lt;br&gt;
Spring's scoped proxy does:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;final class TenantConnection
{
    private WeakMap $byScope;

    public function __construct(private Closure $open)
    {
        $this-&amp;gt;byScope = new WeakMap();
    }

    public function pdo(): PDO
    {
        return $this-&amp;gt;byScope[Scope::getCurrent()] ??= ($this-&amp;gt;open)();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;$open looks at the current request's host (from $_SERVER['HTTP_HOST'] &lt;br&gt;
under vote A, or the framework's request object) and connects to that &lt;br&gt;
customer's database. Every service downstream depends on TenantConnection, &lt;br&gt;
not on a PDO, so none of them is recreated. That is also the one rule, as &lt;br&gt;
in .NET: a singleton must not keep a scoped service it got in its &lt;br&gt;
constructor.&lt;/p&gt;
&lt;p&gt;Doctrine is the one place to be careful: the EntityManager holds request &lt;br&gt;
state (the identity map and the unit of work), so it has to be scoped too, &lt;br&gt;
or entities leak between customers. The expensive parts, metadata, proxies &lt;br&gt;
and configuration, stay shared.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the way to do it would be to have a non-scoped factory layer that implements the Connection interface (and a second one that implements the EntityManager interface) and passes all requests on to a scope-sensitive instance.  And the factory would need to be externalized so that it could check the current scope itself?  Something like:&lt;/p&gt;
&lt;p&gt;class ConnectionProxy implements ConnectionInterface { &lt;br&gt;
private WeakMap $conns;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; public function __construct(private Closure $open) {}

public function executeQuery(string $q, array $args) {
    $this-&amp;gt;getScopedConn()-&amp;gt;executeQuery($q, $args);
}

private function getScopedConn() {
    return $this-&amp;gt;conns[Scope::getCurrent()] ??= ($this-&amp;gt;open)();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;$conn = new ConnectionProxy(function () { &lt;br&gt;
$domain = $_SERVER['domain']; &lt;br&gt;
// Logic to pick the DB here.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;return DriveManager::getConnection(blah);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;});&lt;/p&gt;
&lt;p&gt;Give or take the pool management you mentioned before.&lt;/p&gt;
&lt;p&gt;This is what I'm concerned about.  That looks tricky to get right.  Eg, it looks like I totally forgot to manually initialize the WeakMap in the constructor.  But I suspect this pattern will be common, not just for databases but also for any user-specific objects that get created, like a connection to someone's Mastodon account or whatever.  So this is a pattern we need to work to make as fool-proof as possible, because we're all fools. :-)&lt;/p&gt;
&lt;p&gt;Continuing my brainstorming from above:&lt;/p&gt;
&lt;p&gt;class ConnectionProxy implements ConnectionInterface { &lt;br&gt;
#[Scoped] &lt;br&gt;
private Connection $conn;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; public function __construct(private ConnectionMaker $open) {}

public function executeQuery(string $q, array $args) {
    ($this-&amp;gt;conn ??= $this-&amp;gt;open())-&amp;gt;executeQuery($q, $args);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;class ConnectionMaker { &lt;br&gt;
public function __invoke() { &lt;br&gt;
$domain = $_SERVER['domain']; &lt;br&gt;
// Logic to pick the DB here. &lt;br&gt;
return DriveManager::getConnection(blah); &lt;br&gt;
} &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;That's still not ideal, but has notably fewer moving parts to screw up.&lt;/p&gt;
&lt;p&gt;Though thinking about it, passing a PSR-7 request object to the ConnectionMaker would make it not scope-sensitive; It would &lt;em&gt;have&lt;/em&gt; to work through the superglobals, or some other global call to get a request object.  I'm seeing turtles all the way down here, which has me nervous.&lt;/p&gt;
&lt;p&gt;As I said, still in favor of the concept, but I want to make sure we go down these rabbit holes to ensure the turtles don't get too deep.  (Boy that's an abused metaphor...)&lt;/p&gt;
&lt;p&gt;--Larry Garfield&lt;/p&gt;
</description><guid>5fd5993f-3ef0-453b-9441-c12c93f15797@app.fastmail.com</guid><pubDate>Thu, 29 Oct 2026 12:22:04 +0000</pubDate></item><item><title>[RFC] Scope</title><link>https://externals.io/message/132951</link><description>&lt;blockquote&gt;
&lt;p&gt;do we still want to have &lt;code&gt;run(callable, ...$args)&lt;/code&gt;? &lt;code&gt;run(Closure $c)&lt;/code&gt; would &lt;br&gt;
work just as well&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My preferred way to write it is an arrow function, which shows exactly what &lt;br&gt;
runs inside the scope:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$scope-&amp;gt;run(fn() =&amp;gt; doAThing(1, 2, 4));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But run(doAThing(...), 1, 2, 4) is consistent with the other core APIs: &lt;br&gt;
Fiber::start(), &lt;code&gt;call_user_func()&lt;/code&gt;, &lt;code&gt;register_shutdown_function()&lt;/code&gt; and many &lt;br&gt;
more take the same &amp;quot;$fn, ...$args&amp;quot; pair. Moving away from that pattern &lt;br&gt;
seems worthy of a separate RFC, and I don't think the Scope RFC should be &lt;br&gt;
the first to break ranks.&lt;/p&gt;
&lt;p&gt;It also combines with PFA better than run(Closure $c) would:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function func(int $a, int $b): void {}

// run(Closure $c):
$scope-&amp;gt;run(fn() =&amp;gt; func(1, 2));  // works
$scope-&amp;gt;run(func(1, 2, ...));     // works
$scope-&amp;gt;run(func(1, ...));        // fails: $b is missing

// run(callable $c, mixed ...$args):
$scope-&amp;gt;run(func(...), 1, 2);     // works
$scope-&amp;gt;run(func(1, ?), 2);       // works
$scope-&amp;gt;run(fn() =&amp;gt; func(1, 2));  // works
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every form that works with a closure-only run() works with this one too, &lt;br&gt;
and a partial application with open parameters only works with this one.&lt;/p&gt;
&lt;p&gt;The examples will avoid the PFA form, though, because it reads like a call, &lt;br&gt;
and the difference between running code in the scope and running it before &lt;br&gt;
the scope is entered is three dots:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$scope-&amp;gt;run(doAThing(1, 2, 4, ...)); // doAThing runs in $scope
$scope-&amp;gt;run(doAThing(1, 2, 4));      // doAThing runs in the caller's scope;
                                     // run() gets whatever it returned
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The docblock on Scope::bind() is horribly confusing and clumsy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Agreed, I'll rewrite it. And yes, it is the Closure::bind() idea: it wraps &lt;br&gt;
a closure in an explicit scope, and returns a new closure that always runs &lt;br&gt;
in that scope, whoever calls it. That is sometimes useful, for example when &lt;br&gt;
the closure needs dependency injection from the scope it came from rather &lt;br&gt;
than from the scope it ends up being called in.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;A scope keeps no link to the scope it was run from.&amp;quot; So that fully &lt;br&gt;
precludes getParentScope() and such, yes? What is the reason?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's simple to add in userspace with a WeakMap&amp;lt;Scope, Scope&amp;gt;, for code that &lt;br&gt;
wants a hierarchy. In core it would carry a risk of memory leaks: an app &lt;br&gt;
designed to create each new scope from the previous one, millions of times, &lt;br&gt;
would keep the whole chain alive.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think you mean &amp;quot;PHP process&amp;quot; here&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Under the CLI the root scope is the process, yes. Under php-fpm it is the &lt;br&gt;
request, not the process, which handles many requests. I'll spell out both &lt;br&gt;
cases instead of saying &amp;quot;request&amp;quot;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Am I correct in summarizing it as &amp;quot;a closure inherits the scope of its &lt;br&gt;
callsite, not creation site&amp;quot;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes. Closures don't have a scope; stack frames do. A closure is just code: &lt;br&gt;
while it runs, some scope is current, and later the same closure can run &lt;br&gt;
while another scope is current. What matters is the scope that called it, &lt;br&gt;
since the scope never changes while a function's instructions are running.&lt;/p&gt;
&lt;p&gt;Fibers and generators look different, but follow the same rule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A fiber gets a scope because it will get a stack frame as soon as &lt;br&gt;
$fiber-&amp;gt;start() is called. It is bound to the scope that created it, so &lt;br&gt;
it starts in that scope, whoever starts or resumes it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A generator function is just a function and isn't bound to a scope. But &lt;br&gt;
a Generator is, in a sense, a stack frame: calling the function creates &lt;br&gt;
it, so the Generator object (not the generator function) is bound to the &lt;br&gt;
scope it was created in.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'll add examples for each.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For secondary vote A (the superglobals), the example is very unclear. &lt;br&gt;
[...] Forget to do so and poof&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;$request and $handler are the server's own; I'll make that explicit. The &lt;br&gt;
copying is not something applications do. It is done once, by whatever &lt;br&gt;
creates the request scope: Swerve, FrankenPHP, RoadRunner. That is the same &lt;br&gt;
place that fills the superglobals today.&lt;/p&gt;
&lt;p&gt;A new scope starting with empty superglobals is deliberate. Scopes are a &lt;br&gt;
new feature, and it seems safer to start the scope's globals empty and &lt;br&gt;
require frameworks to populate them, than to start them as clones of the &lt;br&gt;
parent's. Clones would let a parent scope mutate values inside its child &lt;br&gt;
scopes through object properties, and every framework would have to clear &lt;br&gt;
them out first.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The first mention of $GLOBALS is in the superglobal secondary vote &lt;br&gt;
section. [...] I am undecided if I agree globals should not follow the &lt;br&gt;
scope.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'll move that up. Globals and static properties stay shared because &lt;br&gt;
applications use them for caches, registries and singletons. Warming those &lt;br&gt;
once and keeping them across requests is the reason to run in worker mode &lt;br&gt;
at all. If they followed the scope, every request would start cold.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;However, I am still uneasy about how narrow it is. [...] I also fear that &lt;br&gt;
the result is we'll have a lot of subtly-different and incompatible ways &lt;br&gt;
of handling that&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That is what we have today, and it's why I wrote this. I spent two years &lt;br&gt;
trying to do it in userspace with phasync. phasync attaches a context to &lt;br&gt;
each fiber and that context follows every child fiber. It almost works, &lt;br&gt;
but not quite:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A generator passed from one request to another, concurrent request can &lt;br&gt;
produce one value in one fiber and the next in another. A fiber can't &lt;br&gt;
serve as identity from userspace unless developers pass an &lt;br&gt;
identification token as an argument everywhere.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Amp, React and phasync can each provide some identity tying code to a &lt;br&gt;
request/response pair. But then every third-party library has to pick &lt;br&gt;
one, React or Revolt or something else, integrate with it, or add an &lt;br&gt;
adapter layer. That is the incompatibility you describe, and it exists &lt;br&gt;
precisely because core has no such identity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In core it is nearly free. It is fast in ext-scope and slow in &lt;br&gt;
userspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It makes superglobals less global, which has been one of the main &lt;br&gt;
criticisms of PHP for more than a decade.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scope could store values, but then it could quickly become a kind of &lt;br&gt;
service locator and encourage poor design. A WeakMap keyed on Scope &lt;br&gt;
avoids naming conventions for keys, and it limits who can reach &lt;br&gt;
something like a database connection: only the code holding the map.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There will be bugs, but not necessarily subtle ones. When one process &lt;br&gt;
handles 5000 concurrent requests, you can't hand out 5000 PDO &lt;br&gt;
connections; you need a limit on the total and a pool. Scope doesn't &lt;br&gt;
cause that class of bug. High concurrency does, and the community will &lt;br&gt;
have to learn to work with it, as Java, C#, Node and Python did.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;But the RFC examples are all doing a pseudo-global service locator, not &lt;br&gt;
something I am able or willing to do. [...] So what would it look like in &lt;br&gt;
a real dependency injection situation?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's a fair objection, and the examples are to blame: I wrote them to &lt;br&gt;
show the mechanism in as few lines as possible, and they ended up looking &lt;br&gt;
like a service locator. I'm not proposing one, and I'll replace them with &lt;br&gt;
a container example.&lt;/p&gt;
&lt;p&gt;Scope supports the service locator pattern and dependency injection alike; &lt;br&gt;
it doesn't care which one a framework chooses. I think the confusion comes &lt;br&gt;
from where the scope lives. Functions and closures are not bound to a &lt;br&gt;
scope, and neither is the DI container: it isn't bound to the root scope &lt;br&gt;
just because it was built there. When the container is invoked, the call &lt;br&gt;
goes on the stack with the current scope, so the container sees the scope &lt;br&gt;
it was called from.&lt;/p&gt;
&lt;p&gt;That lets a container offer what .NET calls a scoped lifetime: a service &lt;br&gt;
that is neither a singleton shared by all requests nor a transient, but &lt;br&gt;
one instance per request, shared by everything inside that request. The &lt;br&gt;
container keeps those instances in a WeakMap keyed on the Scope, which &lt;br&gt;
users never see.&lt;/p&gt;
&lt;p&gt;This is how other languages do it. The runtime gives each unit of work an &lt;br&gt;
identity that follows it across async boundaries, and the container, not &lt;br&gt;
application code, uses it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;.NET: AsyncLocal&amp;lt;T&amp;gt; flows with the ExecutionContext across awaits. &lt;br&gt;
Microsoft.Extensions.DependencyInjection has ServiceLifetime.Scoped, &lt;br&gt;
&lt;a href="http://ASP.NET" rel="nofollow" target="_blank"&gt;ASP.NET&lt;/a&gt; Core creates one IServiceScope per request, and the container &lt;br&gt;
can refuse a scoped service injected into a singleton (ValidateScopes).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java: Spring's @RequestScope and CDI's @RequestScoped. A singleton gets &lt;br&gt;
a proxy and calls it normally, and the proxy finds the current request's &lt;br&gt;
instance through a ThreadLocal (RequestContextHolder in Spring). &lt;br&gt;
ScopedValue (JEP 506) is the newer primitive for this, and works with &lt;br&gt;
virtual threads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Node: AsyncLocalStorage. NestJS has request-scoped providers &lt;br&gt;
(Scope.REQUEST), awilix has createScope(). TC39's AsyncContext proposal &lt;br&gt;
would put the same thing in JavaScript itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Python: contextvars (PEP 567), which asyncio copies into every task. &lt;br&gt;
Async frameworks and DI libraries keep request-scoped state in it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go passes context.Context explicitly as the first argument everywhere. &lt;br&gt;
That is the alternative, and it is the &amp;quot;identification token as an &lt;br&gt;
argument everywhere&amp;quot; PHP code would need without this RFC.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In none of these do classes look services up through the request &lt;br&gt;
identity: they still get their dependencies through the constructor. PHP &lt;br&gt;
has no such identity today, and that is all the primary vote adds.&lt;/p&gt;
&lt;p&gt;This is a complete PSR-11 container with the three lifetimes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;final class Container implements Psr\Container\ContainerInterface
{
    private array $shared = [];
    private WeakMap $scoped;   // Scope =&amp;gt; that scope's services

    /** @param array&amp;lt;string, array{Closure(self): mixed, 'singleton'|'scoped'|'transient'}&amp;gt; $services */
    public function __construct(private array $services)
    {
        $this-&amp;gt;scoped = new WeakMap();
    }

    public function get(string $id): mixed
    {
        [$make, $lifetime] = $this-&amp;gt;services[$id] ?? throw new NotFound($id);

        if ('scoped' === $lifetime) {
            $mine = $this-&amp;gt;scoped[Scope::getCurrent()] ??= new ArrayObject();

            return $mine[$id] ??= $make($this);
        }

        return 'singleton' === $lifetime ? $this-&amp;gt;shared[$id] ??= $make($this) : $make($this);
    }

    public function has(string $id): bool
    {
        return isset($this-&amp;gt;services[$id]);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A singleton is built once per worker, a scoped service once per request, &lt;br&gt;
and the request's services are freed with its scope, without the container &lt;br&gt;
ever hearing that the request ended.&lt;/p&gt;
&lt;p&gt;For your case, your services stay singletons and are built once per &lt;br&gt;
worker. Only the connection is resolved per request, which is what &lt;br&gt;
Spring's scoped proxy does:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;final class TenantConnection
{
    private WeakMap $byScope;

    public function __construct(private Closure $open)
    {
        $this-&amp;gt;byScope = new WeakMap();
    }

    public function pdo(): PDO
    {
        return $this-&amp;gt;byScope[Scope::getCurrent()] ??= ($this-&amp;gt;open)();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;$open looks at the current request's host (from $_SERVER['HTTP_HOST'] &lt;br&gt;
under vote A, or the framework's request object) and connects to that &lt;br&gt;
customer's database. Every service downstream depends on TenantConnection, &lt;br&gt;
not on a PDO, so none of them is recreated. That is also the one rule, as &lt;br&gt;
in .NET: a singleton must not keep a scoped service it got in its &lt;br&gt;
constructor.&lt;/p&gt;
&lt;p&gt;Doctrine is the one place to be careful: the EntityManager holds request &lt;br&gt;
state (the identity map and the unit of work), so it has to be scoped too, &lt;br&gt;
or entities leak between customers. The expensive parts, metadata, proxies &lt;br&gt;
and configuration, stay shared.&lt;/p&gt;
&lt;p&gt;If you want to see it in practice, this is a complete app for Swerve &lt;br&gt;
(&lt;a href="https://github.com/phasync/swerve" rel="nofollow" target="_blank"&gt;https://github.com/phasync/swerve&lt;/a&gt;), using ext-scope's superglobals:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;?php // swerve.php
while (Swerve\Swerve::accept(null, function () {
    $before = $_GET['name'] ?? '-';
    usleep(500_000);   // other requests run in this worker meanwhile
    $after = $_GET['name'] ?? '-';
    echo &amp;quot;before=$before after=$after\n&amp;quot;;
})) {
}

$ composer require phasync/swerve
$ vendor/bin/swerve --workers=1 swerve.php
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Swerve loads the extension phasync bundles, which includes ext-scope.)&lt;/p&gt;
&lt;p&gt;With one worker, 20 concurrent requests with ?name=req1 to ?name=req20 all &lt;br&gt;
finished in 0.54 seconds, so they really overlapped. Each one printed its &lt;br&gt;
own name before and after the sleep. No request object and no container: &lt;br&gt;
just $_GET, which every request sees as its own.&lt;/p&gt;
&lt;p&gt;Frode&lt;/p&gt;
</description><guid>DU2PR08MB734250C27DDCCCA5B21EF003D96E2@DU2PR08MB7342.eurprd08.prod.outlook.com</guid><pubDate>Thu, 29 Oct 2026 00:09:03 +0000</pubDate></item><item><title>[RFC] Scope</title><link>https://externals.io/message/132950</link><description>&lt;blockquote&gt;
&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to start the discussion on a new RFC:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PHP has no object that represents a request. The request is the period &lt;br&gt;
between startup and shutdown, and its state lives in process-wide &lt;br&gt;
globals. That works while a process handles one request at a time, but &lt;br&gt;
not when one process serves many requests, and least of all when they &lt;br&gt;
overlap.&lt;/p&gt;
&lt;p&gt;The RFC adds Scope: an object that identifies a unit of work, such as &lt;br&gt;
an HTTP request, a queue job or a CLI command. Code can create a scope, &lt;br&gt;
run code in it, and ask which scope it is running in:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(new Scope())-&amp;gt;run($handler, $request);

// anywhere in that request:
$db = $this-&amp;gt;connections[Scope::getCurrent()] ??= new PDO($dsn);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fibers and generators join the scope they are created in, so work a &lt;br&gt;
request spreads over several fibers still belongs to that request, &lt;br&gt;
whichever library or scheduler created them. Code that never creates a &lt;br&gt;
scope runs in the root scope and behaves exactly as today.&lt;/p&gt;
&lt;p&gt;The primary vote adds only the identity. Two secondary votes move &lt;br&gt;
engine state into the scope:&lt;/p&gt;
&lt;p&gt;A. the request superglobals and the session &lt;br&gt;
B. the default locale and timezone&lt;/p&gt;
&lt;p&gt;Other state (output buffers, error handlers, ini values) is left for &lt;br&gt;
later RFCs, so each can be discussed on its own.&lt;/p&gt;
&lt;p&gt;An extension implementing the RFC, including both secondary votes, is &lt;br&gt;
available for PHP 8.2 to 8.5:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/fiber-interop/ext-scope" rel="nofollow" target="_blank"&gt;https://github.com/fiber-interop/ext-scope&lt;/a&gt; &lt;br&gt;
(pie install fiber-interop/ext-scope)&lt;/p&gt;
&lt;p&gt;A userland polyfill is fiber-interop/scope on Packagist. A php-src &lt;br&gt;
pull request will follow before the vote.&lt;/p&gt;
&lt;p&gt;I look forward to your feedback.&lt;/p&gt;
&lt;p&gt;Frode Børli&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Minor thoughts as I read through it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Given that we now have PFA, which means turning pretty much any call into a closure involves just adding ... to it, do we still want to have &lt;code&gt;run(callable, ...$args)&lt;/code&gt;?  &lt;code&gt;run(Closure $c)&lt;/code&gt; would work just as well, and be callable like&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$scope-&amp;gt;run(doAThing(1, 2, 4, ...));&lt;/p&gt;
&lt;p&gt;I'm not certain here, but it's worth considering if we can go a step further now.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The docblock on Scope::bind() is horribly confusing and clumsy.  It took me 5 reads to understand what it was saying.  I &lt;em&gt;think&lt;/em&gt; the idea is to &amp;quot;change&amp;quot; the scope object inside a closure, just like Closure::bind() changes the $this object inside a closure.  Yes?  (And returns new rather than modifying in place, but...)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;A scope keeps no link to the scope it was run from.&amp;quot; So that fully precludes getParentScope() and such, yes?  What is the reason for avoiding that?  (Not that I disagree, but I want to understand why.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;The root scope is a single object that lives as long as the PHP request:&amp;quot; - I think you mean &amp;quot;PHP process&amp;quot; here, as the process is not always isomorphic with an HTTP request.  (Which is the whole reason this proposal exists.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The phrasing and descriptions around closures and what scope they run in is quite confusing.  It really needs better examples.  Am I correct in summarizing it as &amp;quot;a closure inherits the scope of its callsiite, not creation site&amp;quot;?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For secondary vote A (the superglobals), the example is very unclear.  You're &lt;code&gt;use&lt;/code&gt;ing $request and $handler, but those are never defined.  It looks like you're providing no alternative API or automation; really just an under the hood separation of $_GET based on scope.  While I can see the simplicity of that, it also means that basically every scope start would need to do the same copying, unless it was absolutely certain there was no code that will be run it that tries to read those superglobals.  Forget to do so and poof, some legacy garbage function that reads $_POST directly now gets no data and you don't know why.  This feels like a footgun.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The first mention of $GLOBALS is in the superglobal secondary vote section.  Are globals and thus $GLOBALS automatically scoped regardless?  That should be clarified.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Oh, that's mentioned further down in the &amp;quot;what follows scope&amp;quot; section.  That should come way earlier. :-)  I am undecided if I agree globals should not follow the scope.  That feels like the sort of thing you would want to follow scope.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, I think this is a promising approach.  I like that it is narrowly and tightly focused.  However, I am still uneasy about how narrow it is.    I can see the argument for &amp;quot;make your own WeakMap and go away&amp;quot; as an approach.  But I also fear that the result is we'll have a lot of subtly-different and incompatible ways of handling that (say, a multi-fiber server like AmPHP, a DI Container, and a specific service that does weird things for reasons), which could lead to hard-to-diagnose bugs.  I am undecided here.&lt;/p&gt;
&lt;p&gt;As a concrete use case that I have been actively pondering of late: At work, we have an app that switches which DB it connects to per-request, based on the Customer that is specified through the domain name.  (Right now it routes through an env var to a constant, but that I could change.)  That works fine in FPM mode, but would fail horribly in FrankenPHP Worker mode.  Scopes seem like they're the solution to that problem, but I'm not completely clear how they'd operate in practice in that case.  I wouldn't want a different DB connection to cause every service downstream from it to be recreated on every soft-request, as that eliminates the main advantage of worker mode.  But the RFC examples are all doing a pseudo-global service locator, not something I am able or willing to do.  (I doubt I could coax Doctrine into working that way.)  So what would it looks like in a real dependency injection situation?&lt;/p&gt;
&lt;p&gt;--Larry Garfield&lt;/p&gt;
</description><guid>2a3d6a49-2859-441c-9096-d79134f6e9e0@app.fastmail.com</guid><pubDate>Wed, 28 Oct 2026 21:58:18 +0000</pubDate></item><item><title>Proposal for Discussion: Effect Declarations and Capability-Gated Process Execution in PHP</title><link>https://externals.io/message/132949</link><description>&lt;blockquote&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&amp;quot;Effect systems&amp;quot; are a very specific thing in comp sci research.  I'm not sure that what is proposed here counts as such.  (Think exceptions that return to their point of throw after the handler completes.  It seems mainly useful as a way to keep a routine technically-pure while still letting it do useful things.)  There are some academic Haskell-like languages with it, but I don't know of anything in widespread use.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What is described here feels more like gated capabilities, similar to what Wasm does.  It is an interesting concept, but for it to work it would need to integrate at a very low level.  The engine would need to explicitly fail a function that tries calling print without the &amp;quot;I do output&amp;quot; flag, or opening a process without the &amp;quot;I start processes&amp;quot; flag, or reading from the file system without the &amp;quot;I read files&amp;quot; flag.  The biggest issue there is, unsurprisingly, backward compatibility.  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.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, these don't seem quite like algebraic effects. I think there is some modern interest in them again (i.e. Unison), so I would pick a different term to describe them. Capabilities also imply something more like an object capability system to me, so I would also avoid that term.&lt;/p&gt;
</description><guid>814891CB-CCB5-494D-84B5-394F98C62CAA@cmpct.info</guid><pubDate>Wed, 28 Oct 2026 15:51:29 +0000</pubDate></item><item><title>Proposal for Discussion: Effect Declarations and Capability-Gated Process Execution in PHP</title><link>https://externals.io/message/132948</link><description>&lt;blockquote&gt;
&lt;p&gt;Hi Arsan,&lt;/p&gt;
&lt;p&gt;I find the idea interesting, but I have two questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Why introduce new syntax instead of using PHP attributes? Isn't this &lt;br&gt;
exactly the kind of metadata that attributes were designed for? What &lt;br&gt;
would be the advantage of introducing a new language construct?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Are you aware of any existing implementations of a similar effect &lt;br&gt;
system in other programming languages? I'd be interested to see how &lt;br&gt;
other languages approach this problem and whether there are any &lt;br&gt;
established patterns PHP could build upon.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Damian&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start="0"&gt;
&lt;li&gt;
&lt;p&gt;Please do not top post.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Attributes would be useful for static-analysis level enforcement.  Something like:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;#[AllowedEffects(AllowedEffects::Output)] &lt;br&gt;
function doesAThing(string $thing) { &lt;br&gt;
print $thing; &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;And then an SA tool could object if a print statement appears in a method without that attribute on it.  That could be implemented today by any of the SA tools in the ecosystem (though they seem to prefer docblock comments to attributes, unfortunately).&lt;/p&gt;
&lt;p&gt;If we wanted something that is enforced by the language, however, then it would need either a language-enforced attribute or new native syntax.  And the general zeitgeist is that Internals favors new syntax over attributes for things that have a guaranteed-impact rather than just an optional add-on.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&amp;quot;Effect systems&amp;quot; are a very specific thing in comp sci research.  I'm not sure that what is proposed here counts as such.  (Think exceptions that return to their point of throw after the handler completes.  It seems mainly useful as a way to keep a routine technically-pure while still letting it do useful things.)  There are some academic Haskell-like languages with it, but I don't know of anything in widespread use.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What is described here feels more like gated capabilities, similar to what Wasm does.  It is an interesting concept, but for it to work it would need to integrate at a very low level.  The engine would need to explicitly fail a function that tries calling print without the &amp;quot;I do output&amp;quot; flag, or opening a process without the &amp;quot;I start processes&amp;quot; flag, or reading from the file system without the &amp;quot;I read files&amp;quot; flag.  The biggest issue there is, unsurprisingly, backward compatibility.  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.&lt;/p&gt;
&lt;p&gt;As noted, it would also need some way to specify a resource dynamically; the file path accessed will be defined at runtime, for instance.  In the case of Wasm, the runtime itself passes the path to use INTO the application, chroot-style.  (At least I think that's how it works; I'm going off of memory of reading the docs a while back.)  I don't see how PHP could get there without completely unacceptable BC breaks.&lt;/p&gt;
&lt;p&gt;So I like the idea in the abstract, but the first and most important question is how to make something like this piecemeal opt-in and still meaningful.  Because if we can't do that, then we can't do it period.&lt;/p&gt;
&lt;p&gt;--Larry Garfield&lt;/p&gt;
</description><guid>d1b18226-32d7-40c1-9509-357afb28b8bb@app.fastmail.com</guid><pubDate>Wed, 28 Oct 2026 15:41:24 +0000</pubDate></item><item><title>[RFC] openssl_get_channel_binding</title><link>https://externals.io/message/132947</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have created an RFC to add the function openssl_get_channel_binding: &lt;br&gt;
&lt;a href="https://wiki.php.net/rfc/openssl_get_channel_binding" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/openssl_get_channel_binding&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PR: &lt;a href="https://github.com/php/php-src/pull/24035" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24035&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The function exposes data related the an established TLS connection, &lt;br&gt;
making it possible for applications to build on top of the security &lt;br&gt;
provided by TLS. It is needed for SASL mechanisms such as &lt;br&gt;
SCRAM-SHA-256-PLUS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thank you for the RFC. I have given it a read. First things first: Don't &lt;br&gt;
forget to adjust the RFC Status to “Under Discussion” and to link the &lt;br&gt;
discussion thread (&lt;a href="https://news-web.php.net/php.internals/132941" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132941&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Content-wise:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;“The function returns null when the requested type is not applicable &lt;br&gt;
to the connection.”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;An operation that is not applicable sounds like an Exception to me. Is &lt;br&gt;
there currently any other situation where &lt;code&gt;null&lt;/code&gt; is returned?&lt;/p&gt;
&lt;p&gt;Edit: I'm noting that this is already listed under “Rejected Features”. &lt;br&gt;
I'm not sure I agree with the reasoning, though: Exceptions are the &lt;br&gt;
standard way of indicating unsupported operations / error situations and &lt;br&gt;
the Exception hierarchy is specifically designed to be caught.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;“$stream is a stream, but it has no active OpenSSL TLS transport”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That sounds like a programmer error, thus &lt;code&gt;Openssl\OpensslError&lt;/code&gt; (or &lt;br&gt;
potentially ValueError).&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;“An OpenSSL call fails while computing the value”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Is this one reachable in practice or is this more of a generic “catch &lt;br&gt;
all” error that cannot really happen?&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;“Because the second parameter is an enum, the function itself no &lt;br&gt;
longer has an unknown-type error. […]”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This paragraph should probably not be mentioned in the RFC since it &lt;br&gt;
effectively describes a prior version of the PR / describes how enums &lt;br&gt;
work.&lt;/p&gt;
&lt;ol start="5"&gt;
&lt;li&gt;“The backing values preserve interoperability: $type-&amp;gt;value is the &lt;br&gt;
IANA name, so it can be forwarded to SASL or other protocol code &lt;br&gt;
unchanged.”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This indeed seems to be a rare case of a backed enum being the right &lt;br&gt;
choice.&lt;/p&gt;
&lt;ol start="6"&gt;
&lt;li&gt;“Userland code that declares a function with the same name without a &lt;br&gt;
&lt;code&gt;function_exists()&lt;/code&gt; guard would fail with “Cannot redeclare function &lt;br&gt;
openssl_get_channel_binding()”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As I had noted in &lt;a href="https://news-web.php.net/php.internals/132938" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132938&lt;/a&gt;, a &lt;br&gt;
&lt;code&gt;function_exists()&lt;/code&gt; check is no guarantee that the code keeps working, &lt;br&gt;
because the previous userland implementation might do something else. &lt;br&gt;
That should be rephrased - but of course &lt;code&gt;openssl_*()&lt;/code&gt; is reserved by &lt;br&gt;
ext/openssl and defining new symbols is explicitly acceptable as per &lt;br&gt;
policy.&lt;/p&gt;
&lt;ol start="7"&gt;
&lt;li&gt;RFC Impact to “To Existing Extensions”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Are there perhaps any extensions that might want to make use of the new &lt;br&gt;
functionality internally? For example pdo_pgsql, I'm noting that the RFC &lt;br&gt;
mentions tests against PostgreSQL?&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>a93047afe10fd8bd99b35a40b753d713@bastelstu.be</guid><pubDate>Wed, 28 Oct 2026 14:18:12 +0000</pubDate></item><item><title>[RFC] array_partition()</title><link>https://externals.io/message/132946</link><description>&lt;p&gt;Hi Tim,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Please do not &amp;quot;top post&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sorry about that, noted.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One hint for the Wiki: Using &lt;code&gt;&amp;lt;php&amp;gt;&lt;/code&gt; around code will perform the proper &lt;br&gt;
escaping, and will also enable syntax highlighting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks, I've switched that bullet to &amp;lt;php&amp;gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Can you please add another &amp;quot;edge case&amp;quot; &lt;br&gt;
example that clearly shows the reference handling behavior to make sure &lt;br&gt;
every reader is aware of the full implications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Done, in a new &amp;quot;By-reference elements&amp;quot; subsection. It shows that &lt;br&gt;
writing through the result changes the input (and the other way &lt;br&gt;
round), and that a reference which is no longer shared is copied as a &lt;br&gt;
plain value. The outputs in the examples come from running them against &lt;br&gt;
the implementation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'm also not sure, I like the fact that &lt;code&gt;array_partition()&lt;/code&gt; has behavior &lt;br&gt;
that cannot be replicated in userland. I can see the &amp;quot;follow &lt;br&gt;
&lt;code&gt;array_filter()&lt;/code&gt;&amp;quot; argument for consistency, but at the same time &lt;br&gt;
&lt;code&gt;array_find()&lt;/code&gt; is dropping references (I believe)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You're right about &lt;code&gt;array_find()&lt;/code&gt;. I checked the other functions in &lt;br&gt;
ext/standard to see where array_partition() would fit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;keep references:  `array_filter()`, `array_diff_key()`, `array_slice()`,
                  `array_values()`, `array_chunk()`
drop references:  `array_find()`, `array_map()`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the functions that return part of their input as an array all keep &lt;br&gt;
references. &lt;code&gt;array_find()&lt;/code&gt; returns a single value, which can't hold a &lt;br&gt;
reference anyway. I think the strongest argument for keeping them is &lt;br&gt;
that replacing the current &lt;code&gt;array_filter()&lt;/code&gt; + &lt;code&gt;array_diff_key()&lt;/code&gt; idiom with &lt;br&gt;
array_partition() then doesn't change behaviour.&lt;/p&gt;
&lt;p&gt;That said, your point about userland replicability is fair, and &lt;br&gt;
dropping references would be a one-line change. I've added it to &amp;quot;Open &lt;br&gt;
Issues&amp;quot; so it gets settled before a vote, and I'm happy to go with &lt;br&gt;
whatever the list prefers.&lt;/p&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Ayoub&lt;/p&gt;
</description><guid>CAB=6nSbdkTVDuDnQvUrLF7UkmzcM0=bxEAA2FiDPBmAae-fPvA@mail.gmail.com</guid><pubDate>Tue, 27 Oct 2026 16:24:02 +0000</pubDate></item><item><title>[RFC] array_partition()</title><link>https://externals.io/message/132945</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;p&gt;Thank you. One note regarding the mailing list: Please do not “top &lt;br&gt;
post”. Put your reply &lt;em&gt;below&lt;/em&gt; the quoted original parts of the email you &lt;br&gt;
are replying to and cut the quote to the relevant bits, just like I'm &lt;br&gt;
doing here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Fixed the &amp;quot;[[], []]&amp;quot; rendering in &amp;quot;Semantics in detail&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;One hint for the Wiki: Using &lt;code&gt;&amp;lt;php&amp;gt;&lt;/code&gt; around code will perform the proper &lt;br&gt;
escaping, and will also enable syntax highlighting.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Replaced the stub in the proposal with a userland implementation &lt;br&gt;
using foreach. While checking it against the native function, I found &lt;br&gt;
one difference: the native function keeps by-reference elements as &lt;br&gt;
references, like &lt;code&gt;array_filter()&lt;/code&gt;, and the foreach version does not. &lt;br&gt;
The RFC mentions it right below the code.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Good that I asked for the example implementation - and that you spelled &lt;br&gt;
out the difference, because I did not realize the significance of the &lt;br&gt;
“By-reference elements of the input are handled in the same way as in &lt;br&gt;
&lt;code&gt;array_filter()&lt;/code&gt;” in the “Semantics in detail” section - and there is no &lt;br&gt;
corresponding example either. Can you please add another “edge case” &lt;br&gt;
example that clearly shows the reference handling behavior to make sure &lt;br&gt;
every reader is aware of the full implications.&lt;/p&gt;
&lt;p&gt;I'm also not sure, I like the fact that &lt;code&gt;array_partition()&lt;/code&gt; has behavior &lt;br&gt;
that cannot be replicated in userland. I can see the “follow &lt;br&gt;
&lt;code&gt;array_filter()&lt;/code&gt;” argument for consistency, but at the same time &lt;br&gt;
&lt;code&gt;array_find()&lt;/code&gt; is dropping references (I believe) and I also feel that &lt;br&gt;
“filtering an array” (i.e. just removing entries) is semantically &lt;br&gt;
somewhat different than “creating new arrays with the original &lt;br&gt;
elements”. There are probably good arguments for both positions and I'd &lt;br&gt;
like to hear some more opinions from others on this matter.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>899eeb786e008a623f89c20ccf5f247c@bastelstu.be</guid><pubDate>Tue, 27 Oct 2026 16:00:05 +0000</pubDate></item><item><title>[RFC] [Discussion] Query Parameter Manipulation Support</title><link>https://externals.io/message/132944</link><description>&lt;p&gt;Hi Tim,&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;I don't think &lt;code&gt;QueryParamParsingOptions::$maxQueryStringLength&lt;/code&gt; is&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;necessary or useful to have. Checking the input length is easy to do &lt;br&gt;
manually (it's just a &lt;code&gt;strlen()&lt;/code&gt; call) and I don't see a practical way &lt;br&gt;
to abuse the API with large input lengths alone: The API will not “blow &lt;br&gt;
up” inputs into considerably larger data structures, the input strings &lt;br&gt;
are mostly just “copied” over, not too different from e.g. &lt;br&gt;
&lt;code&gt;str_replace()&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was also thinking a lot about whether this option is necessary to have. &lt;br&gt;
My main reason for including it was that people would otherwise easily &lt;br&gt;
forget &lt;br&gt;
to limit the input length, whereas the dedicated option enforces the limit &lt;br&gt;
everywhere.&lt;/p&gt;
&lt;p&gt;So the real question is whether QueryParams really cannot be abused via &lt;br&gt;
long strings, and whether $maxParamCount alone could mitigate those risks &lt;br&gt;
?&lt;/p&gt;
&lt;p&gt;And now by thinking about it more, neither I could identify any specific &lt;br&gt;
vulnerability that &lt;br&gt;
would become possible by not enforcing the upper limit. In the previous &lt;br&gt;
iteration &lt;br&gt;
of the RFC, limiting the length was more useful, because parsing would &lt;br&gt;
have been &lt;br&gt;
a more resource intensive operation due to the requirements of the old &lt;br&gt;
&amp;quot;array API&amp;quot;. &lt;br&gt;
The operations that are performed now during parsing are cheap, so as far &lt;br&gt;
as I can see, &lt;br&gt;
it's possible to get rid of this option if no one can come up with a good &lt;br&gt;
enough use-case.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just after sending my previous reply, I realized that even if parsing long &lt;br&gt;
query strings &lt;br&gt;
isn't an expensive operation on its own, the rest of the operations &lt;br&gt;
supported by &lt;br&gt;
QueryParams may be. For example, sorting by long keys can cause significant &lt;br&gt;
slowdown. &lt;br&gt;
(To be fair: I haven't done any measurements yet). And in the light of the &lt;br&gt;
recent CVEs, &lt;br&gt;
increased memory consumption can cause troubles, so IMO an automatically &lt;br&gt;
enforced &lt;br&gt;
maximum length can still be useful.&lt;/p&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Regarding accepting malformed input: uriparser's own query parameter&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;handling &lt;br&gt;
functions (uriDissectQueryMalloc*()) behave the same way as the RFC currently &lt;br&gt;
proposes. &lt;br&gt;
Unfortunately, I could not really find any reasoning behind this choice of &lt;br&gt;
uriparser.&lt;/p&gt;
&lt;p&gt;To be clear, I don't insist on following uriparser's behavior for RFC 1866 &lt;br&gt;
and RFC 3986 (it's &lt;br&gt;
not an option for WHATWG URL, since it specifies what needs to be done in &lt;br&gt;
every detail), &lt;br&gt;
and probably strict parsing is what is more consistent with the Uri class &lt;br&gt;
indeed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When implementing strict parsing for the RFC-based parsers, I realized that &lt;br&gt;
migration from &lt;br&gt;
the $_GET usage (via Uri\QueryParams::parseRfc1866($_SERVER[&amp;quot;QUERY_STRING&amp;quot;] &lt;br&gt;
?? &amp;quot;&amp;quot;)) &lt;br&gt;
would be more difficult, because parseRfc1866() would start rejecting &lt;br&gt;
malformed input that &lt;br&gt;
PHP's existing query-string parser (php_default_treat_data()) currently &lt;br&gt;
accepts. I'm not really &lt;br&gt;
sure how big an issue this would be in practice, but at least it's worth &lt;br&gt;
pointing out.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One more thing which I'm probably going to change: it turned out that &lt;br&gt;
WHATWG URL specifies &lt;br&gt;
the &lt;code&gt;sort()&lt;/code&gt; method (&lt;a href="https://url.spec.whatwg.org/#dom-urlsearchparams-sort" rel="nofollow" target="_blank"&gt;https://url.spec.whatwg.org/#dom-urlsearchparams-sort&lt;/a&gt;) &lt;br&gt;
which must use UTF-16 based &lt;br&gt;
comparisons (using 2 bytes). It is really not obvious from the WHATWG URL, &lt;br&gt;
only the WHATWG Infra &lt;br&gt;
specification defines it: &lt;br&gt;
&lt;a href="https://infra.spec.whatwg.org/#code-unit-less-than" rel="nofollow" target="_blank"&gt;https://infra.spec.whatwg.org/#code-unit-less-than&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In order to restore compatibility with this requirement, I'd define two &lt;br&gt;
sorting algorithms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sortByBytes(): the currently specified one which would use bytes as the &lt;br&gt;
base of comparison&lt;/li&gt;
&lt;li&gt;sortByUtf16(): the one comparing UTF-16 sequences at once which would be &lt;br&gt;
compatible with WHATWG URL&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;I've now added this to the RFC and also started to implement it (only &lt;br&gt;
locally).&lt;/p&gt;
&lt;p&gt;Máté&lt;/p&gt;
</description><guid>CAH5C8xWbsLZLhECh-yOJO9=h03OCk-dh-B6vD2r0A21tf5p8cg@mail.gmail.com</guid><pubDate>Tue, 27 Oct 2026 13:54:30 +0000</pubDate></item><item><title>[RFC] array_partition()</title><link>https://externals.io/message/132943</link><description>&lt;p&gt;Hi Tim,&lt;/p&gt;
&lt;p&gt;Thank you for the careful read, and for the kind words.&lt;/p&gt;
&lt;p&gt;I've updated the RFC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fixed the &amp;quot;[[], []]&amp;quot; rendering in &amp;quot;Semantics in detail&amp;quot;.&lt;/li&gt;
&lt;li&gt;Added is_string(?) to the arity example. I verified that it works &lt;br&gt;
with the implementation.&lt;/li&gt;
&lt;li&gt;Linked the declined Destructuring Coalesce RFC from the &lt;br&gt;
missing-buckets argument and from &amp;quot;Related RFCs&amp;quot;.&lt;/li&gt;
&lt;li&gt;Rewrote the first paragraph of &amp;quot;Backward Incompatible Changes&amp;quot;: with &lt;br&gt;
or without a &lt;code&gt;function_exists()&lt;/code&gt; guard, an existing userland &lt;br&gt;
array_partition() needs to be checked against the native semantics.&lt;/li&gt;
&lt;li&gt;Replaced the stub in the proposal with a userland implementation &lt;br&gt;
using foreach. While checking it against the native function, I found &lt;br&gt;
one difference: the native function keeps by-reference elements as &lt;br&gt;
references, like &lt;code&gt;array_filter()&lt;/code&gt;, and the foreach version does not. &lt;br&gt;
The RFC mentions it right below the code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Ayoub&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'd like to start the discussion on a new RFC:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/array_partition" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/array_partition&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thank you for your RFC. Incidentally a co-worker has hand-written an &lt;br&gt;
&lt;code&gt;array_partition()&lt;/code&gt; just last week (using two &lt;code&gt;array_filter()&lt;/code&gt; calls), &lt;br&gt;
so clearly there is some appetite for it.&lt;/p&gt;
&lt;p&gt;I've just read the RFC and noticed a small rendering issue in the &lt;br&gt;
“Semantics in detail” section. For the “An empty input” bullet point it &lt;br&gt;
seems you didn't properly escape the code and it was interpreted as Wiki &lt;br&gt;
markup.&lt;/p&gt;
&lt;p&gt;For the arity example, you could add that &lt;code&gt;is_string(?)&lt;/code&gt; with PFA’s &lt;code&gt;?&lt;/code&gt; &lt;br&gt;
placeholder should work, since it behaves like a userland function.&lt;/p&gt;
&lt;p&gt;For the “why not a general grouping function” section, I would like to &lt;br&gt;
point towards the declined &lt;br&gt;
&lt;a href="https://wiki.php.net/rfc/destructuring_coalesce" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/destructuring_coalesce&lt;/a&gt; RFC, which is somewhat &lt;br&gt;
related to the “The buckets are only created when at least one element &lt;br&gt;
falls into them” argument.&lt;/p&gt;
&lt;p&gt;For the “Backward incompatible changes” section, I'd like to note that &lt;br&gt;
even for users defining &lt;code&gt;array_partition&lt;/code&gt; with a &lt;code&gt;function_exists()&lt;/code&gt; &lt;br&gt;
check nothing guarantees that their custom implementation behaves the &lt;br&gt;
same, so they would need to adjust their code either way. This is &lt;br&gt;
acknowledged in the second paragraph, but the initial paragraph is &lt;br&gt;
somewhat misleading. In any case, adding new symbols is not considered a &lt;br&gt;
breaking change as per policy and the arguments for the proposed name &lt;br&gt;
are strong, so this is not a hard blocker (but must be mentioned &lt;br&gt;
nevertheless, as you did).&lt;/p&gt;
&lt;p&gt;Perhaps it would also make sense to extend the stub in the proposal &lt;br&gt;
section to a full “userland polyfill” (using the foreach loop), similar &lt;br&gt;
to what the &lt;code&gt;array_find()&lt;/code&gt; RFC did. This can help make the behavior &lt;br&gt;
clear in a way that pure prose can't.&lt;/p&gt;
&lt;p&gt;Other than these small polishing nits, I don't have anything to remark &lt;br&gt;
about the RFC other than: It's a well-written, well-researched and &lt;br&gt;
well-argued RFC and I'm in favor of the proposal.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CAB=6nSZaKPpc30M3fy2+beALAOyN0iembddZUODNEMoLJ6P0Fg@mail.gmail.com</guid><pubDate>Tue, 27 Oct 2026 10:35:36 +0000</pubDate></item><item><title>Proposal for Discussion: Effect Declarations and Capability-Gated Process Execution in PHP</title><link>https://externals.io/message/132942</link><description>&lt;p&gt;Hi Arsan,&lt;/p&gt;
&lt;p&gt;I find the idea interesting, but I have two questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Why introduce new syntax instead of using PHP attributes? Isn't this &lt;br&gt;
exactly the kind of metadata that attributes were designed for? What would &lt;br&gt;
be the advantage of introducing a new language construct?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Are you aware of any existing implementations of a similar effect system &lt;br&gt;
in other programming languages? I'd be interested to see how other &lt;br&gt;
languages approach this problem and whether there are any established &lt;br&gt;
patterns PHP could build upon.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Damian&lt;/p&gt;
&lt;p&gt;niedz., 25 paź 2026, 14:42 użytkownik Arsan Gamal &lt;a href="mailto:arsan.gamal@gmail.com"&gt;arsan.gamal@gmail.com&lt;/a&gt; &lt;br&gt;
napisał:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello PHP Internals,&lt;/p&gt;
&lt;p&gt;I would like to propose an idea for discussion regarding the introduction &lt;br&gt;
of effect declarations in PHP, with a particular focus on making function &lt;br&gt;
behavior more explicit and improving the security and auditability of &lt;br&gt;
sensitive operations.&lt;/p&gt;
&lt;p&gt;Currently, PHP function signatures describe parameters and return values &lt;br&gt;
but do not indicate which external operations a function may perform. A &lt;br&gt;
function may execute operating-system commands, access the filesystem, or &lt;br&gt;
make network requests through its implementation or dependencies without &lt;br&gt;
these operations being visible in its signature.&lt;/p&gt;
&lt;p&gt;I believe an effect system could help address this limitation by allowing &lt;br&gt;
functions to declare the operations they may perform. These declarations &lt;br&gt;
could support static analysis, contract checking, code auditing, and &lt;br&gt;
potentially stronger security controls. &lt;br&gt;
Proposed syntax&lt;/p&gt;
&lt;p&gt;As an initial proposal, effects could be declared alongside a function's &lt;br&gt;
return type:&lt;/p&gt;
&lt;p&gt;function generateReport(string $input): string &lt;br&gt;
effects [process.execute] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;Effects could also accept parameters to describe the scope of an operation:&lt;/p&gt;
&lt;p&gt;function generateReport(string $input): string &lt;br&gt;
effects [ &lt;br&gt;
process.execute( &lt;br&gt;
commands: ['/usr/bin/report-renderer'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;In this example, the effect declaration indicates that the function may &lt;br&gt;
execute a process, with the declared contract restricting the intended &lt;br&gt;
executable to the report renderer.&lt;/p&gt;
&lt;p&gt;The same concept could be extended to other operations:&lt;/p&gt;
&lt;p&gt;function readConfiguration(): string &lt;br&gt;
effects [ &lt;br&gt;
&lt;a href="http://filesystem.read" rel="nofollow" target="_blank"&gt;filesystem.read&lt;/a&gt;( &lt;br&gt;
paths: ['/etc/myapp/config.json'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;function fetchReport(string $url): string &lt;br&gt;
effects [ &lt;br&gt;
network.request( &lt;br&gt;
hosts: ['&lt;a href="http://api.example.com" rel="nofollow" target="_blank"&gt;api.example.com&lt;/a&gt;'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;These examples are illustrative and are not intended to prescribe the &lt;br&gt;
final grammar. The syntax, supported effect types, parameter formats, and &lt;br&gt;
enforcement rules would need to be discussed and evaluated. &lt;br&gt;
Effect checking and security&lt;/p&gt;
&lt;p&gt;I envision effects serving as explicit contracts describing the operations &lt;br&gt;
a function may perform. A static analyzer or compiler could check whether &lt;br&gt;
implementations and their dependencies respect these declarations, identify &lt;br&gt;
undeclared effects, and make sensitive operations more visible during code &lt;br&gt;
review.&lt;/p&gt;
&lt;p&gt;Parameterized effects could provide additional information about the &lt;br&gt;
intended scope of an operation. For example, a function declaring a &lt;br&gt;
process-execution effect restricted to a particular executable could be &lt;br&gt;
checked for attempts to execute other programs.&lt;/p&gt;
&lt;p&gt;I would also like to explore how this proposal could complement a &lt;br&gt;
capability-based security model. Effects and capabilities would have &lt;br&gt;
separate responsibilities: effects would describe the operations and &lt;br&gt;
constraints associated with a function, while capabilities would determine &lt;br&gt;
which operations are authorized at runtime.&lt;/p&gt;
&lt;p&gt;For example, an application could grant a request handler permission to &lt;br&gt;
execute a specific binary with defined argument constraints and resource &lt;br&gt;
limits. The runtime would enforce that permission when a process is &lt;br&gt;
created, independently of the function's effect declaration.&lt;/p&gt;
&lt;p&gt;This distinction is important because declaring an effect should not &lt;br&gt;
automatically grant authority to perform the operation. Runtime enforcement &lt;br&gt;
would remain necessary for security-sensitive operations, even if static &lt;br&gt;
effect checking were available. &lt;br&gt;
Scope and open questions&lt;/p&gt;
&lt;p&gt;I recognize that PHP's dynamic features, backward-compatibility &lt;br&gt;
requirements, and native extension ecosystem present significant design and &lt;br&gt;
implementation challenges. Some questions that would need further &lt;br&gt;
exploration include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Whether effects should be explicitly declared, inferred, or support &lt;br&gt;
both approaches.&lt;/h2&gt;
&lt;h2&gt;How effects should propagate through function calls, closures, dynamic &lt;br&gt;
calls, and third-party dependencies.&lt;/h2&gt;
&lt;h2&gt;How parameterized effects should be represented and validated.&lt;/h2&gt;
&lt;h2&gt;Whether effect contracts should be enforced by the PHP engine, &lt;br&gt;
external static analysis tools, or a combination of both.&lt;/h2&gt;
&lt;h2&gt;How effects could integrate with runtime capabilities and existing &lt;br&gt;
APIs.&lt;/h2&gt;
&lt;p&gt;How strict enforcement could be introduced without breaking existing &lt;br&gt;
PHP applications.&lt;/p&gt;
&lt;p&gt;The proposal would not, by itself, prevent vulnerabilities within the PHP &lt;br&gt;
engine or native extensions. Any runtime security guarantees would depend &lt;br&gt;
on the coverage and correctness of the enforcement mechanisms.&lt;/p&gt;
&lt;p&gt;I have started drafting an RFC exploring these ideas, using process &lt;br&gt;
execution as an initial use case. I would welcome feedback on whether &lt;br&gt;
effect declarations and parameterized effects would be a worthwhile &lt;br&gt;
direction for PHP, whether the proposed syntax fits the language, and what &lt;br&gt;
scope would be appropriate for an initial RFC.&lt;/p&gt;
&lt;p&gt;If there is interest, I would be happy to share the draft and work on a &lt;br&gt;
proof of concept.&lt;/p&gt;
&lt;p&gt;Thank you for your time and consideration.&lt;/p&gt;
&lt;p&gt;Respectfully yours, &lt;br&gt;
&lt;em&gt;Arsan Gamal&lt;/em&gt; &lt;br&gt;
Senior Software Engineer&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CA+WT9YYMzoLQ=4mGDJXx6fgh_hVXXspa93u3vGbuQ0e9wVc8sA@mail.gmail.com</guid><pubDate>Tue, 27 Oct 2026 09:38:55 +0000</pubDate></item><item><title>[RFC] openssl_get_channel_binding</title><link>https://externals.io/message/132941</link><description>&lt;p&gt;Hello,&lt;/p&gt;
&lt;p&gt;I have created an RFC to add the function openssl_get_channel_binding: &lt;a href="https://wiki.php.net/rfc/openssl_get_channel_binding" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/openssl_get_channel_binding&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PR: &lt;a href="https://github.com/php/php-src/pull/24035" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24035&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The function exposes data related the an established TLS connection, making it possible for applications to build on top of the security provided by TLS. It is needed for SASL mechanisms such as SCRAM-SHA-256-PLUS.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>8a9fcc10-2dce-415d-883d-ba78d6c62fc0@app.fastmail.com</guid><pubDate>Tue, 27 Oct 2026 09:25:46 +0000</pubDate></item><item><title>[RFC] CSV Extension (ext/csv)</title><link>https://externals.io/message/132940</link><description>&lt;p&gt;Hi Tim,&lt;/p&gt;
&lt;p&gt;Thanks for your feedback.&lt;/p&gt;
&lt;p&gt;You're right about the timing. I hadn't fully considered the impact of last &lt;br&gt;
week's security release on the availability of contributors. I'm happy to &lt;br&gt;
postpone the vote to allow more time for discussion.&lt;/p&gt;
&lt;p&gt;Regarding the namespace, I see your point. I chose &amp;quot;Csv&amp;quot; because it is &lt;br&gt;
simple, clearly describes the functionality, and follows a similar approach &lt;br&gt;
to existing namespaces such as &amp;quot;Uri&amp;quot; and &amp;quot;Dom&amp;quot;. However, I'm open to &lt;br&gt;
discussing alternative approaches if a broader naming convention would make &lt;br&gt;
more sense for PHP.&lt;/p&gt;
&lt;p&gt;I also agree that hearing from Gina would be valuable.&lt;/p&gt;
&lt;p&gt;Thanks again for taking the time to share your concerns.&lt;/p&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Damian&lt;/p&gt;
&lt;p&gt;pon., 26 paź 2026, 23:05 użytkownik Tim Düsterhus &lt;a href="mailto:tim@bastelstu.be"&gt;tim@bastelstu.be&lt;/a&gt; &lt;br&gt;
napisał:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The discussion for this RFC started on October 9, and there has been no &lt;br&gt;
further feedback on the mailing list or GitHub for approximately two &lt;br&gt;
weeks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;within those two weeks there was last week’s security release. As with &lt;br&gt;
the Io\Terminal RFC, I suggest to wait with the vote until things have &lt;br&gt;
calmed down.&lt;/p&gt;
&lt;p&gt;See also: &lt;a href="https://news-web.php.net/php.internals/132895" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132895&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unless any new concerns or objections are raised, I intend to open the &lt;br&gt;
vote &lt;br&gt;
on November 2. &lt;br&gt;
I did not have the time to read the RFC due to the above, but one big &lt;br&gt;
concern of mine is the choice of namespace. I'm not sure if “CSV” is an &lt;br&gt;
important and large enough topic to warrant its own core extension and &lt;br&gt;
to reserve another top-level namespace. There might be a way to nicely &lt;br&gt;
group it with something else (e.g. “file format” or ”serialization &lt;br&gt;
format”) and I believe that warrants further discussion and opinion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'd also like to hear from Gina as the original author of the extension &lt;br&gt;
you propose for inclusion in core.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CA+WT9YbtuU0vqXd6YFBn3J3MXjc0x3JPbWji+s0UCf7mjx8PrQ@mail.gmail.com</guid><pubDate>Tue, 27 Oct 2026 07:10:49 +0000</pubDate></item><item><title>[RFC Idea] Formalization moratorium after PHP2Shell (CVE-2026-109618/109619): independent implementations in Rocq/Agda/K/Redex</title><link>https://externals.io/message/132939</link><description>&lt;blockquote&gt;
&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;Summary: &lt;br&gt;
In October 2026 two critical runtime vulnerabilities, CVE-2026-109618 and &lt;br&gt;
CVE-2026-109619 (PHP2Shell, CVSS 9.2, fixed in 8.2.35 / 8.3.36 / 8.4.27 / &lt;br&gt;
8.5.12 on Oct 21), were found in the Zend Memory Manager and HashTable / &lt;br&gt;
session upload progress handling. Not in ext/dom, ext/curl, or any &lt;br&gt;
application — in the allocator and stale request globals. This affects &lt;br&gt;
essentially every SAPI (FPM, mod_php, CGI, FrankenPHP).&lt;/p&gt;
&lt;p&gt;Motivation - mono-implementation brittleness: &lt;br&gt;
PHP is still defined by a single implementation. Efforts like php-langspec &lt;br&gt;
and KPHP were abandoned in the PHP 7 era. Today PHP_CodeSniffer, &lt;br&gt;
PHP-CS-Fixer, and PHP-Parser each maintain their own partial parsers, &lt;br&gt;
PeachPie must add workarounds for Laravel, and HHVM abandoned PHP &lt;br&gt;
compatibility in 2019 to become Hack. Without a second implementation and a &lt;br&gt;
formal spec, we have no way to catch this class of bug early.&lt;/p&gt;
&lt;p&gt;Cost of cosmetic deprecations: &lt;br&gt;
We have just deprecated non-canonical casts: (integer) -&amp;gt; (int), (boolean) &lt;br&gt;
-&amp;gt; (bool), (double) -&amp;gt; (float), (binary) -&amp;gt; (string). They are functionally &lt;br&gt;
identical. While well-intentioned for consistency, each such deprecation &lt;br&gt;
forces churn across tooling and user code. That time is not spent on &lt;br&gt;
reinforcing the base — exactly what PHP2Shell shows we need.&lt;/p&gt;
&lt;p&gt;Proposal:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Impose an immediate embargo on all new features and all cosmetic &lt;br&gt;
deprecations until the mono-implementation situation is rectified. Not &lt;br&gt;
adding a feature cannot break apps. Not deprecating (integer) cannot break &lt;br&gt;
apps. A corrupt allocator can.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;You're asking the maintainers of Zend PHP to stop building Zend PHP and &lt;br&gt;
focus their efforts on building another implementation?&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Complete the spec attempt left behind by &lt;br&gt;
【entity-Facebook¦canonical_name=Facebook】 by reading php-src with AI &lt;br&gt;
assistance.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I agree that this spec should be kept up-to-date. Doing so requires &lt;br&gt;
【entity-volunteers¦canonical_name=volunteers】.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Do not do the old ArtCraft-style clone-in-Rust-first approach. Since &lt;br&gt;
this class of bug was found with AI, and AI can now write directly in &lt;br&gt;
formalized languages, I propose we implement directly in formal frameworks: &lt;br&gt;
a) Extract and standardize the two ground truths: Zend Engine bytecode &lt;br&gt;
and the formal parser. &lt;br&gt;
b) Build 4 independent implementations directly: two operational &lt;br&gt;
semantics in K Semantic Framework and Racket PLT Redex, and two mechanized &lt;br&gt;
definitions in Rocq and Agda. &lt;br&gt;
c) Build a PyPy/Roslyn-style compiler from PHP to bytecode/JS from those &lt;br&gt;
definitions to bootstrap semantics. &lt;br&gt;
d) Cross-test all implementations against php-src tests AND WordPress, &lt;br&gt;
MediaWiki, Laravel, and other major codebases. &lt;br&gt;
e) Demonstrate bootstrapping by using the new implementations to compile &lt;br&gt;
the bootstrapped runtime with itself.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This gives us what other mature runtimes have: .NET has CoreCLR and still &lt;br&gt;
keeps a Mono option to stress-test additions; Python has PyPy, Cython, &lt;br&gt;
Brython. PHP needs the same.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The other implementations exist because the communities built them. The &lt;br&gt;
core developers of the reference implementations didn't decide to stop &lt;br&gt;
building their implementation to build the others. You're asking a group &lt;br&gt;
that's already stretched too thin with limited resources to stretch &lt;br&gt;
themselves further to build and maintain competing implementations.&lt;/p&gt;
&lt;p&gt;All of this is work that companies with the resources to build these &lt;br&gt;
implementations should be doing, contributing them back to the ecosystem &lt;br&gt;
to solve the problems that you've postulated.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am not arguing for permanent stasis, only for sequencing: formalize and &lt;br&gt;
diversify first, then resume features. That is how we prevent irrelevance &lt;br&gt;
for greenfield projects.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Brian&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cheers, &lt;br&gt;
Ben&lt;/p&gt;
</description><guid>20261027024655.645AE1A0045@lists.php.net</guid><pubDate>Tue, 27 Oct 2026 02:46:55 +0000</pubDate></item><item><title>[RFC] array_partition()</title><link>https://externals.io/message/132938</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'd like to start the discussion on a new RFC:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/array_partition" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/array_partition&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thank you for your RFC. Incidentally a co-worker has hand-written an &lt;br&gt;
&lt;code&gt;array_partition()&lt;/code&gt; just last week (using two &lt;code&gt;array_filter()&lt;/code&gt; calls), &lt;br&gt;
so clearly there is some appetite for it.&lt;/p&gt;
&lt;p&gt;I've just read the RFC and noticed a small rendering issue in the &lt;br&gt;
“Semantics in detail” section. For the “An empty input” bullet point it &lt;br&gt;
seems you didn't properly escape the code and it was interpreted as Wiki &lt;br&gt;
markup.&lt;/p&gt;
&lt;p&gt;For the arity example, you could add that &lt;code&gt;is_string(?)&lt;/code&gt; with PFA’s &lt;code&gt;?&lt;/code&gt; &lt;br&gt;
placeholder should work, since it behaves like a userland function.&lt;/p&gt;
&lt;p&gt;For the “why not a general grouping function” section, I would like to &lt;br&gt;
point towards the declined &lt;br&gt;
&lt;a href="https://wiki.php.net/rfc/destructuring_coalesce" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/destructuring_coalesce&lt;/a&gt; RFC, which is somewhat &lt;br&gt;
related to the “The buckets are only created when at least one element &lt;br&gt;
falls into them” argument.&lt;/p&gt;
&lt;p&gt;For the “Backward incompatible changes” section, I'd like to note that &lt;br&gt;
even for users defining &lt;code&gt;array_partition&lt;/code&gt; with a &lt;code&gt;function_exists()&lt;/code&gt; &lt;br&gt;
check nothing guarantees that their custom implementation behaves the &lt;br&gt;
same, so they would need to adjust their code either way. This is &lt;br&gt;
acknowledged in the second paragraph, but the initial paragraph is &lt;br&gt;
somewhat misleading. In any case, adding new symbols is not considered a &lt;br&gt;
breaking change as per policy and the arguments for the proposed name &lt;br&gt;
are strong, so this is not a hard blocker (but must be mentioned &lt;br&gt;
nevertheless, as you did).&lt;/p&gt;
&lt;p&gt;Perhaps it would also make sense to extend the stub in the proposal &lt;br&gt;
section to a full “userland polyfill” (using the foreach loop), similar &lt;br&gt;
to what the &lt;code&gt;array_find()&lt;/code&gt; RFC did. This can help make the behavior &lt;br&gt;
clear in a way that pure prose can't.&lt;/p&gt;
&lt;p&gt;Other than these small polishing nits, I don't have anything to remark &lt;br&gt;
about the RFC other than: It's a well-written, well-researched and &lt;br&gt;
well-argued RFC and I'm in favor of the proposal.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>0d5b306b-c5d0-436e-81ed-c62be0a1b187@bastelstu.be</guid><pubDate>Mon, 26 Oct 2026 22:37:24 +0000</pubDate></item><item><title>[RFC] CSV Extension (ext/csv)</title><link>https://externals.io/message/132937</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The discussion for this RFC started on October 9, and there has been no &lt;br&gt;
further feedback on the mailing list or GitHub for approximately two weeks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;within those two weeks there was last week’s security release. As with &lt;br&gt;
the Io\Terminal RFC, I suggest to wait with the vote until things have &lt;br&gt;
calmed down.&lt;/p&gt;
&lt;p&gt;See also: &lt;a href="https://news-web.php.net/php.internals/132895" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132895&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unless any new concerns or objections are raised, I intend to open the vote &lt;br&gt;
on November 2. &lt;br&gt;
I did not have the time to read the RFC due to the above, but one big &lt;br&gt;
concern of mine is the choice of namespace. I'm not sure if “CSV” is an &lt;br&gt;
important and large enough topic to warrant its own core extension and &lt;br&gt;
to reserve another top-level namespace. There might be a way to nicely &lt;br&gt;
group it with something else (e.g. “file format” or ”serialization &lt;br&gt;
format”) and I believe that warrants further discussion and opinion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'd also like to hear from Gina as the original author of the extension &lt;br&gt;
you propose for inclusion in core.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>b9cfa8c3-2306-4907-ae47-b01b70320962@bastelstu.be</guid><pubDate>Mon, 26 Oct 2026 22:05:42 +0000</pubDate></item><item><title>Proposal for Discussion: Effect Declarations and Capability-Gated Process Execution in PHP</title><link>https://externals.io/message/132936</link><description></description><guid>6303170a-007c-4cb7-8e1c-5e9993efa6a1@email.android.com</guid><pubDate>Mon, 26 Oct 2026 21:38:30 +0000</pubDate></item><item><title>[IDEA] Native async/await syntax on top of Fibers</title><link>https://externals.io/message/132935</link><description>&lt;p&gt;Hi Abbas,&lt;/p&gt;
&lt;p&gt;Thanks for putting a prototype behind the idea.&lt;/p&gt;
&lt;p&gt;I think PHP is already closer to good async than it looks, and that the &lt;br&gt;
best path keeps the property Fibers gave us: no function colouring. Any &lt;br&gt;
function can suspend, and its caller doesn't need to know. That lets &lt;br&gt;
PHP go the way of Go rather than JavaScript: code is written as &lt;br&gt;
ordinary blocking code, and concurrency is chosen at the call site, not &lt;br&gt;
declared on the function.&lt;/p&gt;
&lt;p&gt;This runs today, unchanged, on phasync, Revolt, AMPHP, ReactPHP and &lt;br&gt;
Swoole:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use function fiber\{go, await_all, sleep};

function fetchAll(array $ms): array
{
    $tasks = [];
    foreach ($ms as $m) {
        $tasks[] = go(function () use ($m) {
            sleep($m / 1000);
            return &amp;quot;slept $m ms&amp;quot;;
        });
    }
    return await_all($tasks);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sleep()&lt;/code&gt; is just called, with no await. It suspends the task it runs &lt;br&gt;
in, not the process, and fetchAll() is an ordinary function that its &lt;br&gt;
callers can't tell apart from a blocking one.&lt;/p&gt;
&lt;p&gt;The only reason it is fiber\sleep() and not \sleep() is that PHP's own &lt;br&gt;
&lt;code&gt;sleep()&lt;/code&gt; has no way to tell the scheduler it is about to block. Give &lt;br&gt;
userland a way to be notified when a fiber would otherwise block, and &lt;br&gt;
plain \sleep(), &lt;code&gt;fread()&lt;/code&gt; or PDO::query() behave the same way. At that &lt;br&gt;
point there is nothing left for an await on a function call to do.&lt;/p&gt;
&lt;p&gt;Compare Async\delay() in your proposal. Without the await,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$value = Async\delay($secs);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;doesn't wait at all: $value is a Future, and the code carries on at &lt;br&gt;
once. Every function that returns a Future has that trap, and every &lt;br&gt;
caller has to know which functions are which. That is the colouring, &lt;br&gt;
and it spreads: a library that wants to serve both kinds of code ends &lt;br&gt;
up with two versions of each function.&lt;/p&gt;
&lt;p&gt;I read your point that everyone still picks a userland library as a &lt;br&gt;
frustration with interoperability, and I share it. A library written &lt;br&gt;
for Amp doesn't run on ReactPHP. But that is solvable without new &lt;br&gt;
syntax. The code above is from fiber-interop, a small common API with &lt;br&gt;
an adapter per event loop:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://fiber-interop.github.io/" rel="nofollow" target="_blank"&gt;https://fiber-interop.github.io/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Most of the remaining pieces exist too. PHP even lets userland make &lt;br&gt;
file I/O transparent: phasync/file-streamwrapper replaces the file:// &lt;br&gt;
wrapper, so plain &lt;code&gt;file_get_contents()&lt;/code&gt;/fread() code suspends only its &lt;br&gt;
own fiber:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/phasync/file-streamwrapper" rel="nofollow" target="_blank"&gt;https://github.com/phasync/file-streamwrapper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That works because stream wrappers are a userland extension point. &lt;br&gt;
PDO, curl, mysqli and the socket functions have no such point. What the &lt;br&gt;
language lacks is the interface for them: a standard way for an &lt;br&gt;
internal function that would block the whole process to ask the &lt;br&gt;
userland scheduler to suspend the current fiber, and to be resumed when &lt;br&gt;
its I/O is ready. With that, existing code becomes concurrent without &lt;br&gt;
being rewritten, under whichever event loop the application uses.&lt;/p&gt;
&lt;p&gt;If PHP gets async and await keywords some day, I think they should &lt;br&gt;
launch and join fibers at the call site, not mark functions and await &lt;br&gt;
futures:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$fiber = async some_function(1, 2, 3);
$result = await $fiber;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;some_function() stays an ordinary function. Whether it runs &lt;br&gt;
concurrently is the caller's choice, as with Go's &amp;quot;go&amp;quot;, so nothing is &lt;br&gt;
coloured.&lt;/p&gt;
&lt;p&gt;A request that runs in many fibers also needs to know which request it &lt;br&gt;
belongs to. That is Go's context.Context, and it's what I've just &lt;br&gt;
proposed as the Scope RFC:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Frode Børli&lt;/p&gt;
</description><guid>AS8PR08MB733933E6DA93F66C8C48FA72D9612@AS8PR08MB7339.eurprd08.prod.outlook.com</guid><pubDate>Mon, 26 Oct 2026 16:28:35 +0000</pubDate></item><item><title>[RFC] Scope</title><link>https://externals.io/message/132934</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to start the discussion on a new RFC:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/scope" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/scope&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PHP has no object that represents a request. The request is the period &lt;br&gt;
between startup and shutdown, and its state lives in process-wide &lt;br&gt;
globals. That works while a process handles one request at a time, but &lt;br&gt;
not when one process serves many requests, and least of all when they &lt;br&gt;
overlap.&lt;/p&gt;
&lt;p&gt;The RFC adds Scope: an object that identifies a unit of work, such as &lt;br&gt;
an HTTP request, a queue job or a CLI command. Code can create a scope, &lt;br&gt;
run code in it, and ask which scope it is running in:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(new Scope())-&amp;gt;run($handler, $request);

// anywhere in that request:
$db = $this-&amp;gt;connections[Scope::getCurrent()] ??= new PDO($dsn);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fibers and generators join the scope they are created in, so work a &lt;br&gt;
request spreads over several fibers still belongs to that request, &lt;br&gt;
whichever library or scheduler created them. Code that never creates a &lt;br&gt;
scope runs in the root scope and behaves exactly as today.&lt;/p&gt;
&lt;p&gt;The primary vote adds only the identity. Two secondary votes move &lt;br&gt;
engine state into the scope:&lt;/p&gt;
&lt;p&gt;A. the request superglobals and the session &lt;br&gt;
B. the default locale and timezone&lt;/p&gt;
&lt;p&gt;Other state (output buffers, error handlers, ini values) is left for &lt;br&gt;
later RFCs, so each can be discussed on its own.&lt;/p&gt;
&lt;p&gt;An extension implementing the RFC, including both secondary votes, is &lt;br&gt;
available for PHP 8.2 to 8.5:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/fiber-interop/ext-scope" rel="nofollow" target="_blank"&gt;https://github.com/fiber-interop/ext-scope&lt;/a&gt; &lt;br&gt;
(pie install fiber-interop/ext-scope)&lt;/p&gt;
&lt;p&gt;A userland polyfill is fiber-interop/scope on Packagist. A php-src &lt;br&gt;
pull request will follow before the vote.&lt;/p&gt;
&lt;p&gt;I look forward to your feedback.&lt;/p&gt;
&lt;p&gt;Frode Børli&lt;/p&gt;
</description><guid>AS8PR08MB7339E2A68BE1D6C2324E2BB7D9612@AS8PR08MB7339.eurprd08.prod.outlook.com</guid><pubDate>Mon, 26 Oct 2026 16:03:58 +0000</pubDate></item><item><title>Updated PHP Windows builds for Brotli security fix</title><link>https://externals.io/message/132933</link><description>&lt;p&gt;The PHP team announces the immediate availability of updated Windows &lt;br&gt;
builds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PHP 8.2.35-1&lt;/li&gt;
&lt;li&gt;PHP 8.3.36-1&lt;/li&gt;
&lt;li&gt;PHP 8.4.27-1&lt;/li&gt;
&lt;li&gt;PHP 8.5.12-1&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These builds include Brotli 1.2.1, which fixes CVE-2026-111497, an &lt;br&gt;
out-of-bounds write vulnerability in Brotli decompression.&lt;/p&gt;
&lt;p&gt;On Windows, PHP's cURL extension can invoke the affected decoder when &lt;br&gt;
automatic HTTP response decompression is enabled. This is disabled by &lt;br&gt;
default in cURL, but applications and HTTP client libraries may enable &lt;br&gt;
it.&lt;/p&gt;
&lt;p&gt;PHP Windows users are advised to update to these builds.&lt;/p&gt;
&lt;p&gt;The -1 suffix marks a Windows package rebuild with updated dependencies. &lt;br&gt;
The PHP source and runtime versions have not changed.&lt;/p&gt;
&lt;p&gt;Release announcement: &lt;a href="https://www.php.net/archive/2026.php#2026-10-26-1" rel="nofollow" target="_blank"&gt;https://www.php.net/archive/2026.php#2026-10-26-1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Windows downloads: &lt;a href="https://www.php.net/downloads.php?os=windows" rel="nofollow" target="_blank"&gt;https://www.php.net/downloads.php?os=windows&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Shivam Mathur&lt;/p&gt;
</description><guid>CAF6SVriE5s4HG3SbReS2T+xADLyA45UV8brU5NJhEPHAbTsLMw@mail.gmail.com</guid><pubDate>Mon, 26 Oct 2026 15:49:24 +0000</pubDate></item><item><title>[RFC] CSV Extension (ext/csv)</title><link>https://externals.io/message/132932</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;The discussion for this RFC started on October 9, and there has been no &lt;br&gt;
further feedback on the mailing list or GitHub for approximately two weeks.&lt;/p&gt;
&lt;p&gt;Unless any new concerns or objections are raised, I intend to open the vote &lt;br&gt;
on November 2.&lt;/p&gt;
&lt;p&gt;Thanks to everyone who participated in the discussion.&lt;/p&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Damian&lt;/p&gt;
&lt;p&gt;On Sun, Oct 11, 2026 at 1:50 PM Damian Jóźwiak &amp;lt; &lt;br&gt;
&lt;a href="mailto:damian.jozwiak.lodz@gmail.com" rel="nofollow" target="_blank"&gt;damian.jozwiak.lodz@gmail.com&lt;/a&gt;&amp;gt; wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi everyone,&lt;/p&gt;
&lt;p&gt;Thank you for the feedback, and Artem, for the detailed review and &lt;br&gt;
independent verification of the implementation.&lt;/p&gt;
&lt;p&gt;I think the discussion has raised two important questions: whether these &lt;br&gt;
improvements belong in the existing CSV API or a dedicated extension, and &lt;br&gt;
what an API supporting both files and already-open streams should look like.&lt;/p&gt;
&lt;p&gt;Artem, your point about incremental improvements is fair. The RFC's &lt;br&gt;
statement that the existing behaviour “cannot be fixed without breaking &lt;br&gt;
compatibility” is too broad. Several improvements could be introduced &lt;br&gt;
through additional functions or opt-in behaviour while preserving existing &lt;br&gt;
calls. You are also right that enclosing fields containing spaces is &lt;br&gt;
permitted by RFC 4180, and that locale-independent byte parsing has &lt;br&gt;
different implications for encodings such as Shift_JIS.&lt;/p&gt;
&lt;p&gt;At the same time, PHP has taken the approach of introducing a modern API &lt;br&gt;
alongside an established one when their contracts differ substantially. The &lt;br&gt;
new DOM API, including Dom\Document, coexists with the legacy DOMDocument &lt;br&gt;
API, and the URI extension provides a dedicated API alongside &lt;code&gt;parse_url()&lt;/code&gt;. &lt;br&gt;
These are relevant precedents for giving users clearer semantics without &lt;br&gt;
changing the behaviour of existing applications. Of course, those &lt;br&gt;
precedents do not automatically justify another CSV parser. They do suggest &lt;br&gt;
that improving the existing API and introducing a dedicated one are both &lt;br&gt;
reasonable approaches to evaluate. The question is whether the consistency &lt;br&gt;
and usability of the proposed CSV API justify its maintenance cost.&lt;/p&gt;
&lt;p&gt;My motivation is to provide parsing, serialization, validation and file &lt;br&gt;
handling with consistent, explicit defaults. In particular, the file-based &lt;br&gt;
entry points accept a path and manage the underlying stream, covering the &lt;br&gt;
convenience previously provided by SplFileObject's CSV methods. The &lt;br&gt;
existing &lt;code&gt;fgetcsv()&lt;/code&gt;/fputcsv() functions operate on streams supplied by the &lt;br&gt;
caller. Both use cases deserve support.&lt;/p&gt;
&lt;p&gt;Separately, the remaining overlapping-token writer issue reported on the &lt;br&gt;
PR has been addressed in &lt;br&gt;
&lt;a href="https://github.com/php/php-src/commit/b7866156dc7e77304fe3419edceba6f890b113cb" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/commit/b7866156dc7e77304fe3419edceba6f890b113cb&lt;/a&gt;. &lt;br&gt;
Fields are now enclosed when tokens could form across field/separator &lt;br&gt;
boundaries. Distinguishable overlapping dialects remain supported; &lt;br&gt;
ambiguous combinations such as delimiter &lt;code&gt;xy&lt;/code&gt; with enclosure &lt;code&gt;xyx&lt;/code&gt; are &lt;br&gt;
rejected by both readers and writers. Regression tests cover both &lt;br&gt;
behaviours, and all 92 PHPT tests pass in my local verification.&lt;/p&gt;
&lt;p&gt;With those concerns in mind, I would like to discuss three possible &lt;br&gt;
directions:&lt;/p&gt;
&lt;p&gt;A. Improve the existing API in ext/standard, adding capabilities such as &lt;br&gt;
string serialization, multibyte tokens and opt-in strict parsing, with file &lt;br&gt;
and lazy-reading conveniences considered where needed.&lt;/p&gt;
&lt;p&gt;B. Continue with the dedicated ext/csv proposal, retaining its &lt;br&gt;
function-based API and lazy collection, while adding entry points for &lt;br&gt;
existing streams and resolving the naming questions.&lt;/p&gt;
&lt;p&gt;C. Rework the proposal around an object-oriented API in the Csv namespace, &lt;br&gt;
with explicit file and stream factories and writing methods. Stream &lt;br&gt;
ownership, iteration, validation and string conversion would need to be &lt;br&gt;
specified before this became a concrete voting option.&lt;/p&gt;
&lt;p&gt;My preference remains a dedicated API with consistent semantics, but I am &lt;br&gt;
open to revising its shape or pursuing the existing-API route if that is &lt;br&gt;
the direction the project prefers.&lt;/p&gt;
&lt;p&gt;Would a directional vote between these approaches be useful if discussion &lt;br&gt;
does not establish a clear preference? I would first document the &lt;br&gt;
alternatives and their trade-offs, and agree on the voting format. &lt;br&gt;
Selecting a direction would guide a revised proposal; it would not approve &lt;br&gt;
an API whose details have yet to be reviewed.&lt;/p&gt;
&lt;p&gt;The current RFC does not propose deprecating the existing CSV functions. &lt;br&gt;
Any future consolidation would need its own discussion and an established &lt;br&gt;
migration path, rather than assuming that introducing a new API commits PHP &lt;br&gt;
to removing the old one.&lt;/p&gt;
&lt;p&gt;The goal is to establish a maintainable CSV path for PHP users, including &lt;br&gt;
those migrating from the deprecated SplFileObject methods. I would welcome &lt;br&gt;
your thoughts on which direction best serves that goal.&lt;/p&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Damian&lt;/p&gt;
&lt;p&gt;On Sat, Oct 10, 2026 at 12:38 PM Artem Ukrainskiy &amp;lt; &lt;br&gt;
&lt;a href="mailto:art.ukrainskiy@gmail.com" rel="nofollow" target="_blank"&gt;art.ukrainskiy@gmail.com&lt;/a&gt;&amp;gt; wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This RFC led me to take a closer look at the built-in CSV functions, and &lt;br&gt;
what I found makes me favor a different path to the same goals.&lt;/p&gt;
&lt;p&gt;The RFC argues that their behavior &amp;quot;cannot be fixed without breaking &lt;br&gt;
compatibility&amp;quot;. I went through the list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$escape: already addressed by the PHP 8.4 deprecation; the default &lt;br&gt;
changes to &amp;quot;&amp;quot; in PHP 9.0.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Locale dependence: php/php-src#24207 ( &lt;br&gt;
&lt;a href="https://github.com/php/php-src/pull/24207" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24207&lt;/a&gt;, under review, prompted by &lt;br&gt;
this RFC) removes the per-byte libc lookup for ASCII characters in &lt;br&gt;
ASCII-compatible locales. The remaining isspace() before an opening &lt;br&gt;
enclosure can be replaced with an explicit space/tab check. For non-ASCII &lt;br&gt;
bytes in CJK locales, mbrlen() serves a purpose: a Shift_JIS character can &lt;br&gt;
contain a '|' trail byte without that byte being a delimiter. A &lt;br&gt;
locale-independent byte parser would split it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Single-byte delimiters and enclosures: longer values currently throw &lt;br&gt;
ValueError, so support for multibyte tokens can be added without changing &lt;br&gt;
existing valid calls.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No inverse of &lt;code&gt;str_getcsv()&lt;/code&gt;: a str_putcsv() function would fill that gap &lt;br&gt;
and let SplFileObject::fputcsv() callers use &lt;br&gt;
$file-&amp;gt;fwrite(str_putcsv($row)).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[null] for an empty line and whitespace before an enclosure: these can &lt;br&gt;
be addressed by an opt-in strict mode without changing the default &lt;br&gt;
behavior. Enclosing fields containing spaces on output is permitted by RFC &lt;br&gt;
4180 section 2.5 and is not a compliance defect.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Strict validation, multibyte tokens, string serialization and lazy &lt;br&gt;
reading can all be built on the existing API. Lazy iteration over a stream &lt;br&gt;
already works with a generator around &lt;code&gt;fgetcsv()&lt;/code&gt;; strict row-width &lt;br&gt;
validation can be layered on top. These changes can be developed and &lt;br&gt;
reviewed independently, without replacing the parser or breaking existing &lt;br&gt;
calls.&lt;/p&gt;
&lt;p&gt;I have benchmarks and test scripts for the existing implementation and &lt;br&gt;
the proposed extension here: &lt;br&gt;
&lt;a href="https://github.com/ArtUkrainskiy/php-src-bench/tree/main/reports/csv-pr-24199" rel="nofollow" target="_blank"&gt;https://github.com/ArtUkrainskiy/php-src-bench/tree/main/reports/csv-pr-24199&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Adding ext/csv instead would leave core maintaining two independent CSV &lt;br&gt;
parsers for the foreseeable future. The RFC explicitly leaves the built-ins &lt;br&gt;
unchanged, and the June discussion around the SplFileObject deprecations &lt;br&gt;
showed understandable reluctance to remove existing APIs without an &lt;br&gt;
established migration path (&lt;a href="https://news-web.php.net/php.internals/131503" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/131503&lt;/a&gt;, &lt;br&gt;
and the August follow-up: &lt;a href="https://news-web.php.net/php.internals/132186" rel="nofollow" target="_blank"&gt;https://news-web.php.net/php.internals/132186&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The branch itself is in good shape. The issues I reported on the PR were &lt;br&gt;
addressed quickly, and the parser is now faster than &lt;code&gt;fgetcsv()&lt;/code&gt; in my &lt;br&gt;
benchmarks. This is not an objection to the implementation or the work that &lt;br&gt;
went into it.&lt;/p&gt;
&lt;p&gt;My concern is the long-term maintenance cost of introducing a second &lt;br&gt;
parser when the existing one can be improved incrementally. I'd rather help &lt;br&gt;
land those improvements in ext/standard.&lt;/p&gt;
&lt;p&gt;пт, 9 окт. 2026 г. в 17:07, Damian Jóźwiak &amp;&lt;a href="mailto:lt;damian.jozwiak.lodz@gmail.com" rel="nofollow" target="_blank"&gt;lt;damian.jozwiak.lodz@gmail.com&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to open the discussion on an RFC proposing a dedicated CSV &lt;br&gt;
extension (ext/csv) for PHP core.&lt;/p&gt;
&lt;p&gt;RFC: &lt;a href="https://wiki.php.net/rfc/csv_extension" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/csv_extension&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Implementation: &lt;a href="https://github.com/php/php-src/pull/24199" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24199&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The proposal builds upon Gina Peter Banyard's girgias/csv extension &lt;br&gt;
(BSD-3-Clause), with additional functionality for file and stream handling.&lt;/p&gt;
&lt;p&gt;The motivation includes the deprecation of the SplFileObject CSV &lt;br&gt;
methods in PHP 8.6, which leaves certain use cases without a direct &lt;br&gt;
replacement.&lt;/p&gt;
&lt;p&gt;The proposed extension provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Six functions and one class in the Csv\ namespace.&lt;/h2&gt;
&lt;h2&gt;RFC 4180-compatible parsing and serialization by default.&lt;/h2&gt;
&lt;h2&gt;Locale-independent processing without the proprietary escape &lt;br&gt;
mechanism.&lt;/h2&gt;
&lt;h2&gt;Multibyte delimiters, enclosures, and EOL sequences.&lt;/h2&gt;
&lt;h2&gt;Strict and lax collection parsing.&lt;/h2&gt;
&lt;p&gt;Lazy iteration over CSV files and streaming output.&lt;/p&gt;
&lt;p&gt;The implementation includes PHPT tests covering parsing, serialization, &lt;br&gt;
stream handling, resource lifetime, and various edge cases.&lt;/p&gt;
&lt;p&gt;The pull request's CI checks are currently passing across the tested &lt;br&gt;
platforms, including debug, ZTS, and AddressSanitizer configurations.&lt;/p&gt;
&lt;p&gt;The initial API is deliberately kept small. A more comprehensive &lt;br&gt;
object-oriented Reader/Writer API, including capability-oriented &lt;br&gt;
interfaces, is left for potential future discussion.&lt;/p&gt;
&lt;p&gt;I'd particularly appreciate feedback on the public API design, the &lt;br&gt;
naming of LazyLaxCollection, and whether the extension should be always &lt;br&gt;
enabled or optional at build time.&lt;/p&gt;
&lt;p&gt;For transparency, Gina has not reviewed or endorsed this RFC. Parts of &lt;br&gt;
the implementation were developed with LLM assistance; I have reviewed the &lt;br&gt;
code and take full responsibility for the contribution.&lt;/p&gt;
&lt;p&gt;This is an invitation for discussion, not a call for votes.&lt;/p&gt;
&lt;p&gt;Thanks in advance for your feedback.&lt;/p&gt;
&lt;p&gt;Best regards, &lt;br&gt;
Damian Jóźwiak&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;-- &lt;br&gt;
Best regards, &lt;br&gt;
Artem Ukrainskiy&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
</description><guid>CA+WT9Yb092argM-yaQyHDuyJ4=or1aCyeXVct=paTpferdcdJA@mail.gmail.com</guid><pubDate>Mon, 26 Oct 2026 14:52:24 +0000</pubDate></item><item><title>[RFC] array_partition()</title><link>https://externals.io/message/132931</link><description>&lt;p&gt;Hi mickmackusa,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Instead of potentially creating array_partition() and eventually &lt;br&gt;
array_group(), I feel any benefits of array_partition() should be baked &lt;br&gt;
into an array_group() function for greater utility in a unified function.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thanks for thinking it through. Seeded keys would indeed solve the &lt;br&gt;
missing-bucket problem, and with string labels the result reads well:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;['adults' =&amp;gt; $adults, 'minors' =&amp;gt; $minors] = array_group(
    $users,
    fn($u) =&amp;gt; $u-&amp;gt;age &amp;gt;= 18 ? 'adults' : 'minors',
    ['adults', 'minors'],
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I still think the two-way split deserves its own function, for three &lt;br&gt;
reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Destructuring is by key, not by order. With a boolean callback, the &lt;br&gt;
keys become 1 and 0 whatever order they are seeded in, so &lt;br&gt;
[$adults, $minors] = array_group($users, $predicate, [true, false]) &lt;br&gt;
puts the minors in $adults. You have to switch to labels, as above.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With labels, the callback, the seed list and the destructuring keys &lt;br&gt;
have to agree. A typo ('adult' vs 'adults') silently creates a third &lt;br&gt;
group and leaves one variable empty. array_partition() only needs a &lt;br&gt;
predicate, and its result shape is fixed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PHP already pairs general functions with simpler, specialised ones &lt;br&gt;
for common cases: &lt;code&gt;array_filter()&lt;/code&gt; with &lt;code&gt;array_find()&lt;/code&gt; and &lt;code&gt;array_any()&lt;/code&gt;. &lt;br&gt;
A two-way split is common enough to warrant the same treatment. &lt;br&gt;
It doesn't rule out a future array_group(), which raises its own &lt;br&gt;
design questions (return shape, unknown keys, key preservation).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I'll add the seeded-keys alternative to the RFC's &amp;quot;Why not a general &lt;br&gt;
grouping function?&amp;quot; section.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Ayoub&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I wouldn't be disappointed to see array_partition() added to the language, but the longer I think about it, a well-designed &lt;code&gt;array_group()&lt;/code&gt; function could provide the equivalent behavior as well as afford other than just 2 static groups.&lt;/p&gt;
&lt;p&gt;It seems like the only relevant difference is the fact that array_partition() always returns an indexed array of two arrays without needing to push 2 empty arrays for padding. Theoretically, array_group() might not return any subarrays when there are no qualifying items to retain.  Does array_group() need an optional 3rd parameter which declares an empty array for each nominated grouping key which can be nominated in a particular order? Food for thought.&lt;/p&gt;
&lt;p&gt;Instead of potentially creating array_partition() and eventually array_group(), I feel any benefits of array_partition() should be baked into an array_group() function for greater utility in a unified function.&lt;/p&gt;
&lt;p&gt;mickmackusa&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CAB=6nSanNvX+aa=dwFKuxSHkR61OkF5fKkFeFcWfiD9Js7wFew@mail.gmail.com</guid><pubDate>Mon, 26 Oct 2026 14:34:14 +0000</pubDate></item><item><title>Proposal for Discussion: Effect Declarations and Capability-Gated Process Execution in PHP</title><link>https://externals.io/message/132930</link><description>&lt;p&gt;Hello David,&lt;/p&gt;
&lt;p&gt;Thank you for taking the time to read the proposal and share your &lt;br&gt;
questions. I appreciate the feedback, and I think these are important &lt;br&gt;
points to clarify.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;1. Effects for process execution&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I agree that invoking native binaries should not be encouraged as a default &lt;br&gt;
approach when an API or shared library is more appropriate. My intention is &lt;br&gt;
not to promote process execution, but to make potentially dangerous &lt;br&gt;
operations explicit and controllable.&lt;/p&gt;
&lt;p&gt;The main motivation behind this idea is to explore whether PHP could &lt;br&gt;
provide stronger protection against unintended or unauthorized operations, &lt;br&gt;
including attacks such as PHP2Shell. If an attacker exploits a &lt;br&gt;
vulnerability in an application, the impact could be reduced if the &lt;br&gt;
affected execution context is not authorized to perform sensitive &lt;br&gt;
operations.&lt;/p&gt;
&lt;p&gt;One analogy I have in mind is the permission model used by mobile operating &lt;br&gt;
systems. An application may request internet access, camera access, or &lt;br&gt;
filesystem access, but the operating system determines which permissions it &lt;br&gt;
actually receives. Some applications may have a permission while others do &lt;br&gt;
not.&lt;/p&gt;
&lt;p&gt;Similarly, a PHP application or execution context could be granted specific &lt;br&gt;
capabilities, while sensitive operations would be denied when the required &lt;br&gt;
authorization is absent. Process execution is simply one potential use &lt;br&gt;
case, and perhaps a useful starting point because of its security &lt;br&gt;
implications.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;2. Parameterized effects and configurable values&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I agree with your point about API domains and environment-specific &lt;br&gt;
configuration. Hardcoding a hostname in an effect declaration would create &lt;br&gt;
unnecessary coupling if the endpoint changes between environments or needs &lt;br&gt;
to be updated.&lt;/p&gt;
&lt;p&gt;I would not want effect declarations to replace configuration or require a &lt;br&gt;
language-level versioning change whenever a string value changes.&lt;/p&gt;
&lt;p&gt;Instead, parameterized effects could describe constraints or categories of &lt;br&gt;
operations, with the actual values supplied through configuration or &lt;br&gt;
checked against runtime policy. For example, an effect could indicate that &lt;br&gt;
a function may perform network requests, while the permitted hosts are &lt;br&gt;
determined by the application’s configuration and enforced at runtime.&lt;/p&gt;
&lt;p&gt;The same distinction could apply to filesystem access: an effect could &lt;br&gt;
declare that a function reads files, while a runtime policy determines &lt;br&gt;
which paths are permitted.&lt;/p&gt;
&lt;p&gt;I am open to whether parameterized effects should contain literal &lt;br&gt;
constraints, reference named policies, or simply describe the operation &lt;br&gt;
while leaving authorization to a separate mechanism.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;3. Static analysis versus runtime enforcement&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I agree that static analysis cannot reliably determine every operation in a &lt;br&gt;
dynamic language such as PHP, particularly when behavior depends on runtime &lt;br&gt;
input, dynamic calls, or native extensions. I do not expect PHPStan or &lt;br&gt;
Psalm to replace runtime security enforcement.&lt;/p&gt;
&lt;p&gt;However, I think static analysis could still provide value by identifying &lt;br&gt;
operations that contradict declared effects.&lt;/p&gt;
&lt;p&gt;For example, if a function declares that it only performs calculations, a &lt;br&gt;
static analyzer could flag direct or indirect calls to known &lt;br&gt;
filesystem-reading functions, such as &lt;code&gt;glob()&lt;/code&gt; or &lt;code&gt;file_get_contents()&lt;/code&gt;, where &lt;br&gt;
those calls are identifiable. Similar checks could be applied to network &lt;br&gt;
and process-execution APIs.&lt;/p&gt;
&lt;p&gt;This would not be a complete security guarantee. Dynamic dispatch, indirect &lt;br&gt;
calls, and native extensions would introduce limitations. Runtime &lt;br&gt;
enforcement would therefore be necessary for security-sensitive operations, &lt;br&gt;
with the PHP engine or another trusted runtime mechanism checking whether &lt;br&gt;
the active execution context has the required authority.&lt;/p&gt;
&lt;p&gt;Consider a function exposed through an HTTP endpoint whose responsibility &lt;br&gt;
is only to perform a calculation. Ideally, that function should not be able &lt;br&gt;
to make arbitrary API requests, read arbitrary files, or execute system &lt;br&gt;
commands merely because PHP currently allows those operations. Its &lt;br&gt;
permitted effects and runtime authority should reflect what it actually &lt;br&gt;
needs to do.&lt;/p&gt;
&lt;p&gt;The broader goal is to explore whether PHP could move towards a model where &lt;br&gt;
potentially sensitive operations are both visible in code and constrained &lt;br&gt;
by enforceable permissions, rather than relying exclusively on developers &lt;br&gt;
to remember every possible attack path.&lt;/p&gt;
&lt;p&gt;I realize this raises substantial questions around backward compatibility, &lt;br&gt;
the existing extension ecosystem, and the boundary between language &lt;br&gt;
semantics and runtime security. I do not have all the answers yet, and &lt;br&gt;
feedback like yours is helpful in determining the right direction and scope.&lt;/p&gt;
&lt;p&gt;Thank you again for engaging with the proposal.&lt;/p&gt;
&lt;p&gt;Sincerely, &lt;br&gt;
Arsan Gamal&lt;/p&gt;
&lt;p&gt;Sent from Gmail&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hello Arsan. It sounds very interesting.&lt;/p&gt;
&lt;p&gt;However I have some questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use of effect for binaries: I'm not used to the idea of using PHP to &lt;br&gt;
invoke a Binary. Most of the time it tries to invoke an API or a shared &lt;br&gt;
library or something similar. Is it a good idea to encourage calling native &lt;br&gt;
binaries? (I'm sure some people do it. But adding such as a green check of &lt;br&gt;
&amp;quot;you can do it&amp;quot;, seems a little of).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The use of effect for API call: It is interesting. But what if you want &lt;br&gt;
to update an API endpoint/domain? You would have to manually change it in &lt;br&gt;
the code. Is a SemVer-like (semantic versioning) change necessary for a &lt;br&gt;
string data? As far a I know people get these value from an .env file or &lt;br&gt;
something ? (The &lt;code&gt;&lt;a href="http://filesystem.read" rel="nofollow" target="_blank"&gt;filesystem.read&lt;/a&gt;&lt;/code&gt; you gave seems more appropriate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I'm not sure that any static analyser would be able to check it. Because &lt;br&gt;
these kind of checks are to be done in runtime, right? Does PHPStan or &lt;br&gt;
Psalm for instance do test in runtime? It seems that it would be a &lt;br&gt;
responsibility for the PHP engine/runtime?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What do you think?&lt;/p&gt;
&lt;p&gt;Kind regards, &lt;br&gt;
David Maye&lt;/p&gt;
&lt;p&gt;Hello PHP Internals,&lt;/p&gt;
&lt;p&gt;I would like to propose an idea for discussion regarding the introduction &lt;br&gt;
of effect declarations in PHP, with a particular focus on making function &lt;br&gt;
behavior more explicit and improving the security and auditability of &lt;br&gt;
sensitive operations.&lt;/p&gt;
&lt;p&gt;Currently, PHP function signatures describe parameters and return values &lt;br&gt;
but do not indicate which external operations a function may perform. A &lt;br&gt;
function may execute operating-system commands, access the filesystem, or &lt;br&gt;
make network requests through its implementation or dependencies without &lt;br&gt;
these operations being visible in its signature.&lt;/p&gt;
&lt;p&gt;I believe an effect system could help address this limitation by allowing &lt;br&gt;
functions to declare the operations they may perform. These declarations &lt;br&gt;
could support static analysis, contract checking, code auditing, and &lt;br&gt;
potentially stronger security controls. &lt;br&gt;
Proposed syntax&lt;/p&gt;
&lt;p&gt;As an initial proposal, effects could be declared alongside a function's &lt;br&gt;
return type:&lt;/p&gt;
&lt;p&gt;function generateReport(string $input): string &lt;br&gt;
effects [process.execute] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;Effects could also accept parameters to describe the scope of an operation:&lt;/p&gt;
&lt;p&gt;function generateReport(string $input): string &lt;br&gt;
effects [ &lt;br&gt;
process.execute( &lt;br&gt;
commands: ['/usr/bin/report-renderer'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;In this example, the effect declaration indicates that the function may &lt;br&gt;
execute a process, with the declared contract restricting the intended &lt;br&gt;
executable to the report renderer.&lt;/p&gt;
&lt;p&gt;The same concept could be extended to other operations:&lt;/p&gt;
&lt;p&gt;function readConfiguration(): string &lt;br&gt;
effects [ &lt;br&gt;
&lt;a href="http://filesystem.read" rel="nofollow" target="_blank"&gt;filesystem.read&lt;/a&gt;( &lt;br&gt;
paths: ['/etc/myapp/config.json'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;function fetchReport(string $url): string &lt;br&gt;
effects [ &lt;br&gt;
network.request( &lt;br&gt;
hosts: ['&lt;a href="http://api.example.com" rel="nofollow" target="_blank"&gt;api.example.com&lt;/a&gt;'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;These examples are illustrative and are not intended to prescribe the &lt;br&gt;
final grammar. The syntax, supported effect types, parameter formats, and &lt;br&gt;
enforcement rules would need to be discussed and evaluated. &lt;br&gt;
Effect checking and security&lt;/p&gt;
&lt;p&gt;I envision effects serving as explicit contracts describing the operations &lt;br&gt;
a function may perform. A static analyzer or compiler could check whether &lt;br&gt;
implementations and their dependencies respect these declarations, identify &lt;br&gt;
undeclared effects, and make sensitive operations more visible during code &lt;br&gt;
review.&lt;/p&gt;
&lt;p&gt;Parameterized effects could provide additional information about the &lt;br&gt;
intended scope of an operation. For example, a function declaring a &lt;br&gt;
process-execution effect restricted to a particular executable could be &lt;br&gt;
checked for attempts to execute other programs.&lt;/p&gt;
&lt;p&gt;I would also like to explore how this proposal could complement a &lt;br&gt;
capability-based security model. Effects and capabilities would have &lt;br&gt;
separate responsibilities: effects would describe the operations and &lt;br&gt;
constraints associated with a function, while capabilities would determine &lt;br&gt;
which operations are authorized at runtime.&lt;/p&gt;
&lt;p&gt;For example, an application could grant a request handler permission to &lt;br&gt;
execute a specific binary with defined argument constraints and resource &lt;br&gt;
limits. The runtime would enforce that permission when a process is &lt;br&gt;
created, independently of the function's effect declaration.&lt;/p&gt;
&lt;p&gt;This distinction is important because declaring an effect should not &lt;br&gt;
automatically grant authority to perform the operation. Runtime enforcement &lt;br&gt;
would remain necessary for security-sensitive operations, even if static &lt;br&gt;
effect checking were available. &lt;br&gt;
Scope and open questions&lt;/p&gt;
&lt;p&gt;I recognize that PHP's dynamic features, backward-compatibility &lt;br&gt;
requirements, and native extension ecosystem present significant design and &lt;br&gt;
implementation challenges. Some questions that would need further &lt;br&gt;
exploration include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Whether effects should be explicitly declared, inferred, or support &lt;br&gt;
both approaches.&lt;/h2&gt;
&lt;h2&gt;How effects should propagate through function calls, closures, dynamic &lt;br&gt;
calls, and third-party dependencies.&lt;/h2&gt;
&lt;h2&gt;How parameterized effects should be represented and validated.&lt;/h2&gt;
&lt;h2&gt;Whether effect contracts should be enforced by the PHP engine, &lt;br&gt;
external static analysis tools, or a combination of both.&lt;/h2&gt;
&lt;h2&gt;How effects could integrate with runtime capabilities and existing &lt;br&gt;
APIs.&lt;/h2&gt;
&lt;p&gt;How strict enforcement could be introduced without breaking existing &lt;br&gt;
PHP applications.&lt;/p&gt;
&lt;p&gt;The proposal would not, by itself, prevent vulnerabilities within the PHP &lt;br&gt;
engine or native extensions. Any runtime security guarantees would depend &lt;br&gt;
on the coverage and correctness of the enforcement mechanisms.&lt;/p&gt;
&lt;p&gt;I have started drafting an RFC exploring these ideas, using process &lt;br&gt;
execution as an initial use case. I would welcome feedback on whether &lt;br&gt;
effect declarations and parameterized effects would be a worthwhile &lt;br&gt;
direction for PHP, whether the proposed syntax fits the language, and what &lt;br&gt;
scope would be appropriate for an initial RFC.&lt;/p&gt;
&lt;p&gt;If there is interest, I would be happy to share the draft and work on a &lt;br&gt;
proof of concept.&lt;/p&gt;
&lt;p&gt;Thank you for your time and consideration.&lt;/p&gt;
&lt;p&gt;Respectfully yours, &lt;br&gt;
&lt;em&gt;Arsan Gamal&lt;/em&gt; &lt;br&gt;
Senior Software Engineer&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CAELQn1cw8qeW=AXirwXO_NOcVMtDseEjO+LhXCtxtPSniR=qxw@mail.gmail.com</guid><pubDate>Mon, 26 Oct 2026 13:50:07 +0000</pubDate></item><item><title>Proposal for Discussion: Effect Declarations and Capability-Gated Process Execution in PHP</title><link>https://externals.io/message/132929</link><description></description><guid>3756b458-0940-48ea-baab-9d2e4daeae88@email.android.com</guid><pubDate>Mon, 26 Oct 2026 13:20:03 +0000</pubDate></item><item><title>[RFC] array_partition()</title><link>https://externals.io/message/132928</link><description>&lt;p&gt;I wouldn't be disappointed to see array_partition() added to the language, &lt;br&gt;
but the longer I think about it, a well-designed &lt;code&gt;array_group()&lt;/code&gt; function &lt;br&gt;
could provide the equivalent behavior as well as afford other than just 2 &lt;br&gt;
static groups.&lt;/p&gt;
&lt;p&gt;It seems like the only relevant difference is the fact that &lt;br&gt;
array_partition() always returns an indexed array of two arrays without &lt;br&gt;
needing to push 2 empty arrays for padding. Theoretically, array_group() &lt;br&gt;
might not return any subarrays when there are no qualifying items to &lt;br&gt;
retain.  Does array_group() need an optional 3rd parameter which declares &lt;br&gt;
an empty array for each nominated grouping key which can be nominated in a &lt;br&gt;
particular order? Food for thought.&lt;/p&gt;
&lt;p&gt;Instead of potentially creating array_partition() and eventually &lt;br&gt;
array_group(), I feel any benefits of array_partition() should be baked &lt;br&gt;
into an array_group() function for greater utility in a unified function.&lt;/p&gt;
&lt;p&gt;mickmackusa&lt;/p&gt;
</description><guid>CAKVXxD-UoiLrza2nPstHjWLmeoeZP7KM0mF-3jiR9Vq1h0F84w@mail.gmail.com</guid><pubDate>Mon, 26 Oct 2026 12:26:05 +0000</pubDate></item><item><title>What happens to newcomers' PRs in php-src — a year of data</title><link>https://externals.io/message/132927</link><description>&lt;blockquote&gt;
&lt;p&gt;I looked at a year of newcomers' work&lt;/p&gt;
&lt;p&gt;125 PRs are inactive&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The most friction I had as a newish contributor was what happens after you create a pull request, and nobody responds to it. I have quite some trouble getting my PRs reviewed.&lt;/p&gt;
&lt;p&gt;I also dislike the asymmetry where a single poorly motivated objection can cause an author months of RFC paperwork.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>5af875cd-9bde-4538-9fe1-14e60ea1551c@app.fastmail.com</guid><pubDate>Mon, 26 Oct 2026 08:07:49 +0000</pubDate></item><item><title>What happens to newcomers' PRs in php-src — a year of data</title><link>https://externals.io/message/132926</link><description>&lt;p&gt;Hi all,&lt;/p&gt;
&lt;p&gt;#24613 &lt;a href="https://github.com/php/php-src/pull/24613"&gt;https://github.com/php/php-src/pull/24613&lt;/a&gt; (the duplicate-PR &lt;br&gt;
policy) got me wondering what actually happens to PRs &lt;br&gt;
from people coming to php-src for the first time. I looked at a year of &lt;br&gt;
newcomers' work, and the data seemed interesting enough to share.&lt;/p&gt;
&lt;p&gt;Scope: every PR opened between 24 Oct 2025 and 24 Oct 2026 whose author &lt;br&gt;
opened &lt;br&gt;
their very first php-src PR within that window. That's 831 PRs from 219 &lt;br&gt;
people, &lt;br&gt;
about a quarter of all PRs in the period.&lt;/p&gt;
&lt;p&gt;Key observations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Of 831 PRs, 418 were accepted, 157 closed without a merge, and the rest &lt;br&gt;
have &lt;br&gt;
no outcome yet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More newcomers keep arriving: first-time contributors grew from 1–5 a week &lt;br&gt;
early on to 5–12 by autumn, 219 over the year. PR volume followed, from &lt;br&gt;
2–5 a &lt;br&gt;
week to 30–70.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Of the 157 closed, a reason was stated in the discussion for 124. The &lt;br&gt;
biggest &lt;br&gt;
groups: the change isn't wanted (38), the author closed it themselves &lt;br&gt;
(34), &lt;br&gt;
duplicates (31). Most &amp;quot;no&amp;quot;s are about fit or process (out of scope, needs &lt;br&gt;
an &lt;br&gt;
RFC, wrong target branch), not code quality. PRs called outright wrong in &lt;br&gt;
the &lt;br&gt;
code are rare.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Newcomers write tests more often than the repo overall — 68% vs 52%.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PRs with AI-written descriptions (113, about 14%) are accepted noticeably &lt;br&gt;
less &lt;br&gt;
often: around 20% vs 55%.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;143 of 219 newcomers opened exactly 1 PR, 76 more than one, but 47 of &lt;br&gt;
them did &lt;br&gt;
it in a single day. 362 of 831 PRs were opened by people who fired off a &lt;br&gt;
pile &lt;br&gt;
at once.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The top 10 authors opened 487 of 831 PRs (59%) and are accepted at 67%, &lt;br&gt;
while &lt;br&gt;
the other 209 authors sit at 27% (344 PRs).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;One author opened 232 PRs with 84% acceptance — that's 28% of all &lt;br&gt;
newcomer PRs &lt;br&gt;
and 46% of the accepted ones; without him overall acceptance drops from &lt;br&gt;
50% &lt;br&gt;
to 37%.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Acceptance depends a lot on which PR it is for the author: the first PR &lt;br&gt;
29%, &lt;br&gt;
but after a first accepted one 66%. It's the first success that matters, &lt;br&gt;
not &lt;br&gt;
just continuing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;125 PRs are inactive (closed after silence, or open and idle for 50+ &lt;br&gt;
days).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reaction speed tracks resolution: a first maintainer response within a &lt;br&gt;
day → &lt;br&gt;
median close ~20h, versus ~32 days when it takes over a week (Spearman &lt;br&gt;
0.53).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Full write-up, charts and method: &lt;br&gt;
&lt;a href="https://artukrainskiy.github.io/posts/newcomer-prs-in-php-src/" rel="nofollow" target="_blank"&gt;https://artukrainskiy.github.io/posts/newcomer-prs-in-php-src/&lt;/a&gt; &lt;br&gt;
Raw per-PR data: &lt;br&gt;
&lt;a href="https://docs.google.com/spreadsheets/d/185nNwTnj-E6FNjAYLzPZ7ly4QJzEP9iHoUbPgHrrnR4/edit?usp=sharing" rel="nofollow" target="_blank"&gt;https://docs.google.com/spreadsheets/d/185nNwTnj-E6FNjAYLzPZ7ly4QJzEP9iHoUbPgHrrnR4/edit?usp=sharing&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If there's interest, I'm happy to dig deeper so the numbers are solid &lt;br&gt;
enough to &lt;br&gt;
draw conclusions from. I can also share the classification prompts and the &lt;br&gt;
scripts if that's useful.&lt;/p&gt;
&lt;p&gt;One idea I'd like to put up for consideration, and I'd like to know if it'd &lt;br&gt;
be &lt;br&gt;
welcome. A bot that, when a PR opens, checks the mechanical things — no &lt;br&gt;
tests, a &lt;br&gt;
weak or empty description, no benchmarks in a PR aimed at optimization, the &lt;br&gt;
wrong &lt;br&gt;
target branch, an obvious duplicate — and leaves the author a note right &lt;br&gt;
away. It &lt;br&gt;
wouldn't judge whether a change is wanted, and it wouldn't add review time. &lt;br&gt;
Part &lt;br&gt;
of this can be done &amp;quot;for free&amp;quot; without an LLM, and by my rough estimate &lt;br&gt;
even a &lt;br&gt;
first-pass LLM review could be cheap enough.&lt;/p&gt;
&lt;p&gt;An instant note there could spare maintainers the trivial round-trips and &lt;br&gt;
let &lt;br&gt;
contributors fix things before anyone even looks. My study suggests a fast &lt;br&gt;
response leads to a faster close, and with the number of newcomers trending &lt;br&gt;
up &lt;br&gt;
this would help offload maintainers, at least on first-pass reviews and &lt;br&gt;
trivial &lt;br&gt;
checks. Larger projects already do this.&lt;/p&gt;
&lt;p&gt;Is it worth prototyping?&lt;/p&gt;
&lt;p&gt;-- &lt;br&gt;
Best regards, &lt;br&gt;
Artem Ukrainskiy&lt;/p&gt;
</description><guid>CAPen=wFTid2k5zgtWw1qnw62b8+tPOzAcY=HY=LMXMZtD5oXpQ@mail.gmail.com</guid><pubDate>Sun, 25 Oct 2026 18:38:48 +0000</pubDate></item><item><title>From mono-implementation risk to spec: Lessons from CVE-2026-109618/109619 and a path to K/Redex semantics[Idea]</title><link>https://externals.io/message/132925</link><description>&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;PHP today has no formal specification. As the KPHP work &lt;br&gt;
(Filaretti et al., ECOOP'14) notes, Zend is the de-facto &lt;br&gt;
spec. That makes this class of bug hard to catch: &lt;br&gt;
... &lt;br&gt;
I am proposing we use this incident to start:&lt;/p&gt;
&lt;p&gt;A) Formalize Zend bytecode and parser as a living spec &lt;br&gt;
B) Reference executable semantics in two formal frameworks:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think PHP is not starved for bugs. The bottleneck is bugfixes. As I &lt;br&gt;
understand it the problems leading to these CVEs were already found by &lt;br&gt;
an earlier security test, but the problem was coming up with a good &lt;br&gt;
fix. I think creating a spec and a second implementation is not the &lt;br&gt;
most efficient way to find and solve bugs.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To be blunt, the way to address the bottlenecks on bug fixing is to badger PHP-using companies into becoming significant PHP Foundation sponsors.  Or dedicating their own employees full time to PHP maintenance.&lt;/p&gt;
&lt;p&gt;This is a money problem, just like most major OSS projects.  It's nothing more complicated than that.  A formal spec may have merit, but it has no relevance to the current situation.&lt;/p&gt;
&lt;p&gt;--Larry Garfield&lt;/p&gt;
</description><guid>48029991-d584-4741-a805-542b426265d0@app.fastmail.com</guid><pubDate>Sun, 25 Oct 2026 17:12:26 +0000</pubDate></item><item><title>From mono-implementation risk to spec: Lessons from CVE-2026-109618/109619 and a path to K/Redex semantics[Idea]</title><link>https://externals.io/message/132924</link><description>&lt;blockquote&gt;
&lt;p&gt;PHP today has no formal specification. As the KPHP work &lt;br&gt;
(Filaretti et al., ECOOP'14) notes, Zend is the de-facto &lt;br&gt;
spec. That makes this class of bug hard to catch: &lt;br&gt;
... &lt;br&gt;
I am proposing we use this incident to start:&lt;/p&gt;
&lt;p&gt;A) Formalize Zend bytecode and parser as a living spec &lt;br&gt;
B) Reference executable semantics in two formal frameworks:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think PHP is not starved for bugs. The bottleneck is bugfixes. As I understand it the problems leading to these CVEs were already found by an earlier security test, but the problem was coming up with a good fix. I think creating a spec and a second implementation is not the most efficient way to find and solve bugs.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>ef176734-12d5-4036-b860-2daf2d6e911b@app.fastmail.com</guid><pubDate>Sun, 25 Oct 2026 15:32:42 +0000</pubDate></item><item><title>[RFC] array_partition()</title><link>https://externals.io/message/132923</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to start the discussion on a new RFC:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/array_partition" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/array_partition&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It proposes a function that splits an array into the elements for which &lt;br&gt;
a callback returns a truthy value and those for which it does not, in a &lt;br&gt;
single pass:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function array_partition(array $array, callable $callback): array {}

[$adults, $minors] = array_partition($users, fn($u) =&amp;gt; $u-&amp;gt;age &amp;gt;= 18);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keys are preserved, and the callback receives the value and the key, &lt;br&gt;
following &lt;code&gt;array_find()&lt;/code&gt;. The result is always a list of two arrays, with &lt;br&gt;
the matching elements first, as in Ruby, Kotlin, Rust, Haskell and &lt;br&gt;
Laravel's Collection::partition().&lt;/p&gt;
&lt;p&gt;The RFC also covers the points raised in the karma request thread: &lt;br&gt;
why it is a two-way split rather than a general grouping function, why &lt;br&gt;
the result is not keyed by true/false, and the $callback parameter &lt;br&gt;
name. It also discusses the previous userland uses of the name &lt;br&gt;
array_partition() with an &amp;quot;N chunks&amp;quot; meaning.&lt;/p&gt;
&lt;p&gt;The implementation is at &lt;a href="https://github.com/php/php-src/pull/24568" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24568&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to Ilija for granting the karma, and to everyone who commented &lt;br&gt;
on the earlier thread. I look forward to your feedback.&lt;/p&gt;
&lt;p&gt;Ayoub&lt;/p&gt;
</description><guid>CAB=6nSYev=m6iH7TFrHy0j0gAmzjJ3qGpuODhEaHKTFts3V4mw@mail.gmail.com</guid><pubDate>Sun, 25 Oct 2026 13:38:55 +0000</pubDate></item><item><title>Proposal for Discussion: Effect Declarations and Capability-Gated Process Execution in PHP</title><link>https://externals.io/message/132922</link><description>&lt;p&gt;Hello PHP Internals,&lt;/p&gt;
&lt;p&gt;I would like to propose an idea for discussion regarding the introduction &lt;br&gt;
of effect declarations in PHP, with a particular focus on making function &lt;br&gt;
behavior more explicit and improving the security and auditability of &lt;br&gt;
sensitive operations.&lt;/p&gt;
&lt;p&gt;Currently, PHP function signatures describe parameters and return values &lt;br&gt;
but do not indicate which external operations a function may perform. A &lt;br&gt;
function may execute operating-system commands, access the filesystem, or &lt;br&gt;
make network requests through its implementation or dependencies without &lt;br&gt;
these operations being visible in its signature.&lt;/p&gt;
&lt;p&gt;I believe an effect system could help address this limitation by allowing &lt;br&gt;
functions to declare the operations they may perform. These declarations &lt;br&gt;
could support static analysis, contract checking, code auditing, and &lt;br&gt;
potentially stronger security controls. &lt;br&gt;
Proposed syntax&lt;/p&gt;
&lt;p&gt;As an initial proposal, effects could be declared alongside a function's &lt;br&gt;
return type:&lt;/p&gt;
&lt;p&gt;function generateReport(string $input): string &lt;br&gt;
effects [process.execute] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;Effects could also accept parameters to describe the scope of an operation:&lt;/p&gt;
&lt;p&gt;function generateReport(string $input): string &lt;br&gt;
effects [ &lt;br&gt;
process.execute( &lt;br&gt;
commands: ['/usr/bin/report-renderer'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;In this example, the effect declaration indicates that the function may &lt;br&gt;
execute a process, with the declared contract restricting the intended &lt;br&gt;
executable to the report renderer.&lt;/p&gt;
&lt;p&gt;The same concept could be extended to other operations:&lt;/p&gt;
&lt;p&gt;function readConfiguration(): string &lt;br&gt;
effects [ &lt;br&gt;
&lt;a href="http://filesystem.read" rel="nofollow" target="_blank"&gt;filesystem.read&lt;/a&gt;( &lt;br&gt;
paths: ['/etc/myapp/config.json'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;function fetchReport(string $url): string &lt;br&gt;
effects [ &lt;br&gt;
network.request( &lt;br&gt;
hosts: ['&lt;a href="http://api.example.com" rel="nofollow" target="_blank"&gt;api.example.com&lt;/a&gt;'] &lt;br&gt;
) &lt;br&gt;
] &lt;br&gt;
{ &lt;br&gt;
// Implementation &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;These examples are illustrative and are not intended to prescribe the final &lt;br&gt;
grammar. The syntax, supported effect types, parameter formats, and &lt;br&gt;
enforcement rules would need to be discussed and evaluated. &lt;br&gt;
Effect checking and security&lt;/p&gt;
&lt;p&gt;I envision effects serving as explicit contracts describing the operations &lt;br&gt;
a function may perform. A static analyzer or compiler could check whether &lt;br&gt;
implementations and their dependencies respect these declarations, identify &lt;br&gt;
undeclared effects, and make sensitive operations more visible during code &lt;br&gt;
review.&lt;/p&gt;
&lt;p&gt;Parameterized effects could provide additional information about the &lt;br&gt;
intended scope of an operation. For example, a function declaring a &lt;br&gt;
process-execution effect restricted to a particular executable could be &lt;br&gt;
checked for attempts to execute other programs.&lt;/p&gt;
&lt;p&gt;I would also like to explore how this proposal could complement a &lt;br&gt;
capability-based security model. Effects and capabilities would have &lt;br&gt;
separate responsibilities: effects would describe the operations and &lt;br&gt;
constraints associated with a function, while capabilities would determine &lt;br&gt;
which operations are authorized at runtime.&lt;/p&gt;
&lt;p&gt;For example, an application could grant a request handler permission to &lt;br&gt;
execute a specific binary with defined argument constraints and resource &lt;br&gt;
limits. The runtime would enforce that permission when a process is &lt;br&gt;
created, independently of the function's effect declaration.&lt;/p&gt;
&lt;p&gt;This distinction is important because declaring an effect should not &lt;br&gt;
automatically grant authority to perform the operation. Runtime enforcement &lt;br&gt;
would remain necessary for security-sensitive operations, even if static &lt;br&gt;
effect checking were available. &lt;br&gt;
Scope and open questions&lt;/p&gt;
&lt;p&gt;I recognize that PHP's dynamic features, backward-compatibility &lt;br&gt;
requirements, and native extension ecosystem present significant design and &lt;br&gt;
implementation challenges. Some questions that would need further &lt;br&gt;
exploration include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Whether effects should be explicitly declared, inferred, or support both &lt;br&gt;
approaches.&lt;/h2&gt;
&lt;h2&gt;How effects should propagate through function calls, closures, dynamic &lt;br&gt;
calls, and third-party dependencies.&lt;/h2&gt;
&lt;h2&gt;How parameterized effects should be represented and validated.&lt;/h2&gt;
&lt;h2&gt;Whether effect contracts should be enforced by the PHP engine, external &lt;br&gt;
static analysis tools, or a combination of both.&lt;/h2&gt;
&lt;h2&gt;How effects could integrate with runtime capabilities and existing APIs.&lt;/h2&gt;
&lt;p&gt;How strict enforcement could be introduced without breaking existing PHP &lt;br&gt;
applications.&lt;/p&gt;
&lt;p&gt;The proposal would not, by itself, prevent vulnerabilities within the PHP &lt;br&gt;
engine or native extensions. Any runtime security guarantees would depend &lt;br&gt;
on the coverage and correctness of the enforcement mechanisms.&lt;/p&gt;
&lt;p&gt;I have started drafting an RFC exploring these ideas, using process &lt;br&gt;
execution as an initial use case. I would welcome feedback on whether &lt;br&gt;
effect declarations and parameterized effects would be a worthwhile &lt;br&gt;
direction for PHP, whether the proposed syntax fits the language, and what &lt;br&gt;
scope would be appropriate for an initial RFC.&lt;/p&gt;
&lt;p&gt;If there is interest, I would be happy to share the draft and work on a &lt;br&gt;
proof of concept.&lt;/p&gt;
&lt;p&gt;Thank you for your time and consideration.&lt;/p&gt;
&lt;p&gt;Respectfully yours, &lt;br&gt;
&lt;em&gt;Arsan Gamal&lt;/em&gt; &lt;br&gt;
Senior Software Engineer&lt;/p&gt;
</description><guid>CAELQn1eJRFCd7_dW1MfG8SyP5G+rUbqUw7AkptB7wp5YAzo5dg@mail.gmail.com</guid><pubDate>Sun, 25 Oct 2026 13:38:09 +0000</pubDate></item><item><title>From mono-implementation risk to spec: Lessons from CVE-2026-109618/109619 and a path to K/Redex semantics[Idea]</title><link>https://externals.io/message/132921</link><description>&lt;p&gt;Hi Brian,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The vulnerable pattern — count-before-alloc + OOM bailout — &lt;br&gt;
could have been modeled and fuzzed if the invariants of &lt;br&gt;
HashTable and ZendMM were specified outside of C.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It seems to be that the memory manager and internal structures are exactly the part that would vary between implementations. PHPNG (the basis of 7.0) heavily rewrote exactly those parts; an implementation on top of another runtime like .net or JVM would naturally make use of their underlying memory management; a rewrite in fully-checked Rust or Zig would use different mechanisms than one in C. A meaningful spec would cover all of those, asserting that the behaviour observed from the outside matches.&lt;/p&gt;
&lt;p&gt;I can't see how a specification would have helped here, any more than the HTML Specification helps prevent memory management bugs in browser implementations.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;.NET is a useful counter-example, not because &amp;quot;Microsoft &lt;br&gt;
exists&amp;quot;, but because it chose to keep alternative runtimes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Microsoft employs about 200_000 people. If 0.01% of those are paid to work full time on .NET, that's still twice as many as have ever been paid to work full time on PHP.&lt;/p&gt;
&lt;p&gt;If someone came along offering to create a competing implementation of PHP, I would beg them to instead spend the effort improving the one we already have.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Rowan Tommins &lt;br&gt;
[IMSoP]&lt;/p&gt;
</description><guid>5DADCCCA-6621-4405-9713-4BDF61024725@rwec.co.uk</guid><pubDate>Sun, 25 Oct 2026 12:41:47 +0000</pubDate></item><item><title>[RFC Idea] Formalization moratorium after PHP2Shell (CVE-2026-109618/109619): independent implementations in Rocq/Agda/K/Redex</title><link>https://externals.io/message/132920</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;Summary: &lt;br&gt;
In October 2026 two critical runtime vulnerabilities, CVE-2026-109618 and &lt;br&gt;
CVE-2026-109619 (PHP2Shell, CVSS 9.2, fixed in 8.2.35 / 8.3.36 / 8.4.27 / &lt;br&gt;
8.5.12 on Oct 21), were found in the Zend Memory Manager and HashTable / &lt;br&gt;
session upload progress handling. Not in ext/dom, ext/curl, or any &lt;br&gt;
application — in the allocator and stale request globals. This affects &lt;br&gt;
essentially every SAPI (FPM, mod_php, CGI, FrankenPHP).&lt;/p&gt;
&lt;p&gt;Motivation - mono-implementation brittleness: &lt;br&gt;
PHP is still defined by a single implementation. Efforts like php-langspec &lt;br&gt;
and KPHP were abandoned in the PHP 7 era. Today PHP_CodeSniffer, &lt;br&gt;
PHP-CS-Fixer, and PHP-Parser each maintain their own partial parsers, &lt;br&gt;
PeachPie must add workarounds for Laravel, and HHVM abandoned PHP &lt;br&gt;
compatibility in 2019 to become Hack. Without a second implementation and a &lt;br&gt;
formal spec, we have no way to catch this class of bug early.&lt;/p&gt;
&lt;p&gt;Cost of cosmetic deprecations: &lt;br&gt;
We have just deprecated non-canonical casts: (integer) -&amp;gt; (int), (boolean) &lt;br&gt;
-&amp;gt; (bool), (double) -&amp;gt; (float), (binary) -&amp;gt; (string). They are functionally &lt;br&gt;
identical. While well-intentioned for consistency, each such deprecation &lt;br&gt;
forces churn across tooling and user code. That time is not spent on &lt;br&gt;
reinforcing the base — exactly what PHP2Shell shows we need.&lt;/p&gt;
&lt;p&gt;Proposal:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Impose an immediate embargo on all new features and all cosmetic &lt;br&gt;
deprecations until the mono-implementation situation is rectified. Not &lt;br&gt;
adding a feature cannot break apps. Not deprecating (integer) cannot break &lt;br&gt;
apps. A corrupt allocator can.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Complete the spec attempt left behind by &lt;br&gt;
【entity-Facebook¦canonical_name=Facebook】 by reading php-src with AI &lt;br&gt;
assistance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Do not do the old ArtCraft-style clone-in-Rust-first approach. Since &lt;br&gt;
this class of bug was found with AI, and AI can now write directly in &lt;br&gt;
formalized languages, I propose we implement directly in formal frameworks: &lt;br&gt;
a) Extract and standardize the two ground truths: Zend Engine bytecode &lt;br&gt;
and the formal parser. &lt;br&gt;
b) Build 4 independent implementations directly: two operational &lt;br&gt;
semantics in K Semantic Framework and Racket PLT Redex, and two mechanized &lt;br&gt;
definitions in Rocq and Agda. &lt;br&gt;
c) Build a PyPy/Roslyn-style compiler from PHP to bytecode/JS from those &lt;br&gt;
definitions to bootstrap semantics. &lt;br&gt;
d) Cross-test all implementations against php-src tests AND WordPress, &lt;br&gt;
MediaWiki, Laravel, and other major codebases. &lt;br&gt;
e) Demonstrate bootstrapping by using the new implementations to compile &lt;br&gt;
the bootstrapped runtime with itself.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This gives us what other mature runtimes have: .NET has CoreCLR and still &lt;br&gt;
keeps a Mono option to stress-test additions; Python has PyPy, Cython, &lt;br&gt;
Brython. PHP needs the same.&lt;/p&gt;
&lt;p&gt;I am not arguing for permanent stasis, only for sequencing: formalize and &lt;br&gt;
diversify first, then resume features. That is how we prevent irrelevance &lt;br&gt;
for greenfield projects.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Brian&lt;/p&gt;
</description><guid>CAL0FH+097CVJ1=Xnd9axxpRpBLf-sgK1dFPEdLammMT8F85G8Q@mail.gmail.com</guid><pubDate>Sun, 25 Oct 2026 08:30:17 +0000</pubDate></item><item><title>RFC karma request: array_partition()</title><link>https://externals.io/message/132919</link><description>&lt;p&gt;Hi Ayoub&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'd like to request RFC karma on the wiki to propose a new function, &lt;br&gt;
array_partition(). My wiki username is: ayoubezzini&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;RFC karma was granted, good luck!&lt;/p&gt;
&lt;p&gt;Ilija&lt;/p&gt;
</description><guid>5885185d-b121-407c-a6cf-25e2f1a6f533@gmail.com</guid><pubDate>Sun, 25 Oct 2026 00:36:43 +0000</pubDate></item><item><title>RFC karma request</title><link>https://externals.io/message/132918</link><description>&lt;p&gt;Hi Frode&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I would like to request RFC karma for my wiki account, frodeborli.&lt;/p&gt;
&lt;p&gt;I intend to publish an RFC called &amp;quot;Scope&amp;quot;, introducing a notion of &lt;br&gt;
logical operation identity to PHP, independent of fibers and &lt;br&gt;
generators, but preserved across their execution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sorry that I missed your request, it's been pretty stressful last few &lt;br&gt;
weeks.&lt;/p&gt;
&lt;p&gt;RFC karma was granted, good luck!&lt;/p&gt;
&lt;p&gt;Ilija&lt;/p&gt;
</description><guid>b3863b50-641f-4ac8-b1a1-142fea77c13d@gmail.com</guid><pubDate>Sun, 25 Oct 2026 00:35:47 +0000</pubDate></item><item><title>From mono-implementation risk to spec: Lessons from CVE-2026-109618/109619 and a path to K/Redex semantics[Idea]</title><link>https://externals.io/message/132917</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I want to raise a broader process question following the &lt;br&gt;
emergency releases on Oct 21 for CVE-2026-109618 and &lt;br&gt;
CVE-2026-109619.&lt;/p&gt;
&lt;p&gt;I had noted privately back in 2020 that given the lack of a &lt;br&gt;
formal spec and single-implementation status, I expected the &lt;br&gt;
next critical vulnerability to be in the language runtime and &lt;br&gt;
execution layer itself — not in ext/dom, ext/curl, ext/gd, &lt;br&gt;
or HTTP handling — but in memory allocation and hashtable &lt;br&gt;
management. The October disclosures matched that pattern, &lt;br&gt;
which is why I'm writing now.&lt;/p&gt;
&lt;p&gt;What happened:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CVE-2026-109618 (CVSS 9.2, &amp;quot;rawkey&amp;quot;): in Zend Engine's &lt;br&gt;
HashTable implementation, _zend_hash_str_add_or_update_i &lt;br&gt;
increments the entry count &lt;em&gt;before&lt;/em&gt; allocating the new &lt;br&gt;
key. If that allocation exceeds memory_limit, Zend calls &lt;br&gt;
zend_bailout() via longjmp, abandoning the request with a &lt;br&gt;
counted-but-uninitialized bucket. Request shutdown then &lt;br&gt;
treats stale memory as a valid zend_string. Requires a &lt;br&gt;
POST with a large field name (&amp;gt;1MB).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CVE-2026-109619 (CVSS 9.2, &amp;quot;stale global state&amp;quot;): in &lt;br&gt;
session.upload_progress, request-owned state is retained &lt;br&gt;
after free and reused by a later request on the same &lt;br&gt;
worker. Small body (~450 bytes).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fixed in 8.2.35, 8.3.36, 8.4.27, 8.5.12. The advisories note &lt;br&gt;
the underlying code goes back to PHP 5.4. Exploitation is &lt;br&gt;
below the application layer — mod_php was confirmed &lt;br&gt;
exploitable before any application code runs.&lt;/p&gt;
&lt;p&gt;This is not a bug in an extension. It is a bug in ZendMM, &lt;br&gt;
zend_hash, and request lifecycle — the core runtime.&lt;/p&gt;
&lt;p&gt;Why this matters beyond the patch:&lt;/p&gt;
&lt;p&gt;PHP today has no formal specification. As the KPHP work &lt;br&gt;
(Filaretti et al., ECOOP'14) notes, Zend is the de-facto &lt;br&gt;
spec. That makes this class of bug hard to catch:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;No alternative implementation to disagree with Zend. &lt;br&gt;
Python has CPython/PyPy/Cython, JavaScript has &lt;br&gt;
V8/SpiderMonkey/JSC, .NET has CoreCLR/Mono. PHP had &lt;br&gt;
HHVM and has PeachPie (.NET), but without a stable &lt;br&gt;
bytecode/parser spec, compatibility diverged — HHVM &lt;br&gt;
dropped PHP compat in 2019 to become Hack, PeachPie &lt;br&gt;
needs workarounds for Laravel. We are back to one &lt;br&gt;
reference implementation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No stable bytecode spec for independent tooling. The &lt;br&gt;
vulnerable pattern — count-before-alloc + OOM bailout — &lt;br&gt;
could have been modeled and fuzzed if the invariants of &lt;br&gt;
HashTable and ZendMM were specified outside of C.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The broader ecosystem point:&lt;/p&gt;
&lt;p&gt;.NET is a useful counter-example, not because &amp;quot;Microsoft &lt;br&gt;
exists&amp;quot;, but because it chose to keep alternative runtimes. &lt;br&gt;
.NET Framework was proprietary and Windows-only. Mono (2001) &lt;br&gt;
was the independent implementation that pushed it open. &lt;br&gt;
Microsoft open-sourced .NET Core in 2014, it became truly &lt;br&gt;
cross-platform (&lt;a href="http://ASP.NET" rel="nofollow" target="_blank"&gt;ASP.NET&lt;/a&gt; Core on Linux/macOS/Windows), and &lt;br&gt;
today .NET intentionally ships both CoreCLR and Mono runtimes &lt;br&gt;
to stress-test feature additions. The .NET Foundation model &lt;br&gt;
is similar to what the PHP Foundation has been building &lt;br&gt;
since 2021.&lt;/p&gt;
&lt;p&gt;PHP's trajectory was the opposite: we lost the second &lt;br&gt;
implementation. The cost is not that PHP becomes &amp;quot;irrelevant&amp;quot; &lt;br&gt;
overnight — it powers a huge share of the web — but that &lt;br&gt;
trust erosion makes teams choose Node/Python/Go for new &lt;br&gt;
systems while keeping PHP for existing WordPress installs. &lt;br&gt;
Long-lived runtime RCEs accelerate that.&lt;/p&gt;
&lt;p&gt;Why I think a spec effort is more tractable now:&lt;/p&gt;
&lt;p&gt;The CVE-2026-109618 lead was flagged by automated audit &lt;br&gt;
tooling (Ryan Austin's agent flagged the count-before-alloc &lt;br&gt;
in _zend_hash_str_add_or_update_i). AI-assisted auditing of &lt;br&gt;
the Zend heap path is now practical.&lt;/p&gt;
&lt;p&gt;Similarly, recent AI-assisted re-implementations of legacy &lt;br&gt;
binary formats and apps from scratch (e.g., ArtCraft's work &lt;br&gt;
cloning apps and data formats in Rust with no legacy code) &lt;br&gt;
show that re-implementing a complex legacy format from a &lt;br&gt;
reference implementation + test suite is more feasible today &lt;br&gt;
than when KPHP was manually written in 2014.&lt;/p&gt;
&lt;p&gt;We can leverage that to bootstrap PHP semantics.&lt;/p&gt;
&lt;p&gt;Proposal for discussion, not an embargo:&lt;/p&gt;
&lt;p&gt;I am not proposing freezing features or cosmetic deprecations. &lt;br&gt;
I am proposing we use this incident to start:&lt;/p&gt;
&lt;p&gt;A) Formalize Zend bytecode and parser as a living spec &lt;br&gt;
extracted from php-src (8.4/8.5 baseline), including &lt;br&gt;
OOM/bailout semantics.&lt;/p&gt;
&lt;p&gt;B) Reference executable semantics in two formal frameworks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;K Framework (building on KPHP)&lt;/li&gt;
&lt;li&gt;PLT Redex / Racket, to cross-check the model &lt;br&gt;
Both should model HashTable invariants, ZendMM alloc &lt;br&gt;
failure, and request lifecycle.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C) PyPy/Roslyn-style bootstrapping: a compiler from PHP to &lt;br&gt;
Zend bytecode and to other targets (e.g., JS) to validate &lt;br&gt;
semantics, plus self-hosting tests (compile the bootstrap &lt;br&gt;
compiler with itself).&lt;/p&gt;
&lt;p&gt;D) Conformance via differential testing: run phpt plus &lt;br&gt;
WordPress, MediaWiki, Laravel, Symfony against any &lt;br&gt;
alternative runtime, not just phpt.&lt;/p&gt;
&lt;p&gt;If there is interest, I can draft a short RFC outline for &lt;br&gt;
(A) + (B) as a first step, and talk to the PHP Foundation &lt;br&gt;
(&lt;a href="mailto:contact@thephp.foundation" rel="nofollow" target="_blank"&gt;contact@thephp.foundation&lt;/a&gt;) about whether this is fundable &lt;br&gt;
as Foundation work.&lt;/p&gt;
&lt;p&gt;Thanks for reading this long mail,&lt;/p&gt;
&lt;p&gt;Brian&lt;/p&gt;
</description><guid>CAL0FH+1SbwKYqdK0VF7dRyS+NgGLVMp53kExL1j0PEYKJc+T1Q@mail.gmail.com</guid><pubDate>Sat, 24 Oct 2026 20:59:35 +0000</pubDate></item><item><title>[RFC] Io\Terminal</title><link>https://externals.io/message/132916</link><description>&lt;p&gt;Hi Sjoerd,&lt;/p&gt;
&lt;p&gt;I've pushed fixes for the issues you pointed out, along with regression tests.&lt;/p&gt;
&lt;p&gt;Zero-timeout reads now handle already-available escape sequences &lt;br&gt;
without waiting, and getSize() no longer suppresses a pending resize &lt;br&gt;
notification.&lt;/p&gt;
&lt;p&gt;While testing, I also found that incomplete UTF-8 at EOF could cause &lt;br&gt;
readKey() to keep returning null. It now throws TerminalException on &lt;br&gt;
EOF, while genuine timeouts still preserve the partial bytes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/php/php-src/pull/23941" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/23941&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thanks again for the careful review.&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Pratik&lt;/p&gt;
&lt;p&gt;On Fri, 23 Oct 2026 16:44:51 -0700, Pratik Bhujel &lt;br&gt;
&lt;a href="mailto:prateekbhujelpb@gmail.com"&gt;prateekbhujelpb@gmail.com&lt;/a&gt; wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi Sjoerd,&lt;/p&gt;
&lt;p&gt;Thanks for taking a look. &lt;br&gt;
Perhaps it would be desirable to distinguish between the user cancelling, and a genuine error, and perhaps also EOF; for example with subclasses of TerminalException. &lt;br&gt;
Yes, I see the use case. An application may handle a cancelled password prompt quietly but report an I/O failure. Currently they all throw TerminalException, and the messages are not stable identifiers. Separate subclasses would allow that distinction while keeping TerminalException as the common catch. I would like to settle this before the vote. &lt;br&gt;
Is this sufficiently long, even when used over SSH or such? Is this configurable in readSecret as well? &lt;br&gt;
The 25 ms starts after Escape arrives, so it is not a limit on the SSH round trip. Delayed fragments can still exceed it. readKey() lets you increase sequenceTimeout, within the overall timeout.&lt;/p&gt;
&lt;p&gt;readSecret() currently uses a fixed 25 ms wait in its byte-stream escape handling. It is not separately configurable, and increasing the overall timeout does not increase that wait. That is a limitation worth addressing. Native Windows console input uses input records, so this escape-sequence timing does not apply there. &lt;br&gt;
If I resize the terminal twice, do I get two Key::Resize? getSize() seems to update the stored size of the terminal. Do I still get a Key::Resize after I call getSize()? &lt;br&gt;
Not necessarily two. On POSIX, resize notifications can be coalesced, and changes between reads can be detected by comparing dimensions.&lt;/p&gt;
&lt;p&gt;You are right about getSize(). It updates the same cached dimensions, so calling it first can hide a change from that comparison. Windows can still have queued resize records. I think getSize() should query the size without acknowledging a pending notification. That needs fixing and documenting. Resize should mean &amp;quot;check the current size&amp;quot;, rather than promise a count of every resize. &lt;br&gt;
This would not work with escape sequences, right? Or does it work correctly if the key is already buffered? &lt;br&gt;
Reading the current byte-stream decoder, the zero deadline makes it return Escape before checking the remaining bytes, even if the whole sequence is buffered. The focused zero-timeout test covers a lone Escape.&lt;/p&gt;
&lt;p&gt;Zero should prevent waiting while still allowing a complete available sequence to be decoded. That needs a focused regression test and a fix.&lt;/p&gt;
&lt;p&gt;I’ll follow up with the test results and changes. These findings are from checking the code; I haven’t run the new reproducers yet.&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Pratik&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CA+9BsNfqeMv+innpEwgVmjuaSB5X9+fGM4xENV=swCPi-PwUtg@mail.gmail.com</guid><pubDate>Sat, 24 Oct 2026 17:12:25 +0000</pubDate></item><item><title>[RFC] Paren-less access to scalar extension methods ('a,b'-&gt;arr as sugar for 'a,b'-&gt;arr())</title><link>https://externals.io/message/132915</link><description>&lt;blockquote&gt;
&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;This follows up on the Extension Methods / Scalar Extension Methods RFCs (currently in draft). I'd like to propose allowing extension methods on scalar values to be invoked through property-fetch syntax, with the parentheses omitted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I'd be a strong -1 on this. It seems like an entirely arbitrary rule, to save two characters per call, making the language less consistent, and closing off syntax that might be useful for something else in future.&lt;/p&gt;
&lt;p&gt;It also seems odd to propose it now, as an extension to something that doesn't even exist yet. Surely there are much more &amp;quot;critical path&amp;quot; details of extension and scalar methods that we need to iron out before thinking about such extra sugar?&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Rowan Tommins &lt;br&gt;
[IMSoP]&lt;/p&gt;
</description><guid>46FDD5A5-6F9C-4B9E-884E-24B6EA1442E6@rwec.co.uk</guid><pubDate>Sat, 24 Oct 2026 13:26:06 +0000</pubDate></item><item><title>RFC karma request: array_partition()</title><link>https://externals.io/message/132914</link><description>&lt;p&gt;Hi Morgan,&lt;/p&gt;
&lt;p&gt;Thanks for the support!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;my partition functions also map passes and rejects to true and false &lt;br&gt;
respectively (so the result is a mapping from booleans to array values).&lt;/p&gt;
&lt;p&gt;[true =&amp;gt; $passed, false =&amp;gt; $rejected] = array_partition(...);&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I looked at this, and the catch is that boolean array keys are cast to &lt;br&gt;
integers, so true =&amp;gt; 1 and false =&amp;gt; 0. A boolean-keyed result would &lt;br&gt;
therefore have to put the rejected elements at index 0, and then &lt;br&gt;
positional destructuring silently gives the opposite of what it reads:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[$adults, $minors] = array_partition($users, fn($u) =&amp;gt; $u-&amp;gt;age &amp;gt;= 18);
// with a bool-keyed result, $adults would hold the minors
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whichever layout is chosen, one of the two idioms ends up swapped. I'd &lt;br&gt;
rather keep &amp;quot;matching first&amp;quot; at index 0, since that's what Ruby, Kotlin, &lt;br&gt;
Rust, Haskell and Laravel all return, and it makes the plain &lt;br&gt;
[$matching, $rest] destructuring work. I'll document the pitfall &lt;br&gt;
explicitly in the RFC, with your example, so nobody reaches for &lt;br&gt;
[true =&amp;gt; ..., false =&amp;gt; ...] expecting it to work.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I would also prefer the callback parameter to be named $predicate, to &lt;br&gt;
emphasise that it is supposed to return a boolean.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I agree it's more descriptive in isolation. But every other array &lt;br&gt;
function taking a callback names it $callback, including &lt;code&gt;array_filter()&lt;/code&gt; &lt;br&gt;
and the recent &lt;code&gt;array_find()&lt;/code&gt;, &lt;code&gt;array_find_key()&lt;/code&gt;, &lt;code&gt;array_any()&lt;/code&gt; and &lt;br&gt;
&lt;code&gt;array_all()&lt;/code&gt;, which are also predicates. With named arguments I think &lt;br&gt;
it's more valuable that callback: works the same way across the whole &lt;br&gt;
family, so I'd prefer to keep $callback for consistency. I'll mention &lt;br&gt;
it in the RFC as a considered alternative.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Ayoub&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi Ayoub,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It feels unintuitive that &lt;code&gt;true&lt;/code&gt; callback outcomes map to the &lt;code&gt;0&lt;/code&gt; key &lt;br&gt;
and &lt;code&gt;false&lt;/code&gt; outcomes map to &lt;code&gt;1&lt;/code&gt;. &lt;br&gt;
I'm also in support, and this would have been my only observation: my &lt;br&gt;
partition functions also map passes and rejects to true and false &lt;br&gt;
respectively (so the result is a mapping from booleans to array values).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;If that mapping were retained, it could be documented in code as&lt;/p&gt;
&lt;p&gt;[true =&amp;gt; $passed, false =&amp;gt; $rejected] = array_partition(...);&lt;/p&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;p&gt;$adult_tested = array_partition(...);&lt;/p&gt;
&lt;p&gt;$adults = $adult_tested[true]; &lt;br&gt;
$minors = $adult_tested[false];&lt;/p&gt;
&lt;p&gt;I would also prefer the callback parameter to be named $predicate, to &lt;br&gt;
emphasise that it is supposed to return a boolean. $callback doesn't &lt;br&gt;
convey as much about what it's for - the same name is used, for example, &lt;br&gt;
in &lt;code&gt;usort()&lt;/code&gt;, where it's a comparator. It didn't matter until named &lt;br&gt;
parameters became a thing.&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CAB=6nSZ3MKhuRfpd6MiY9DeBRbiBn9xCy8XzQ9tYVpNWorEOdQ@mail.gmail.com</guid><pubDate>Sat, 24 Oct 2026 13:18:40 +0000</pubDate></item><item><title>[RFC] Paren-less access to scalar extension methods ('a,b'-&gt;arr as sugar for 'a,b'-&gt;arr())</title><link>https://externals.io/message/132913</link><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;This follows up on the Extension Methods / Scalar Extension Methods RFCs (currently in draft). I'd like to propose allowing extension methods on scalar values to be invoked through property-fetch syntax, with the parentheses omitted.&lt;/p&gt;
&lt;p&gt;Proposal: when a property read on a scalar fails, fall back to the extension method registry and invoke the method with its default arguments. -&amp;gt;name becomes sugar for -&amp;gt;name().&lt;/p&gt;
&lt;p&gt;extension string $s { &lt;br&gt;
    public function arr(string $separator = ','): array { &lt;br&gt;
        return explode($separator, $s); &lt;br&gt;
    } &lt;br&gt;
}&lt;/p&gt;
&lt;p&gt;'a,b'-&amp;gt;arr;        // ['a', 'b']   &amp;lt;- new &lt;br&gt;
'a,b'-&amp;gt;arr();      // ['a', 'b']   &amp;lt;- already works &lt;br&gt;
'a|b'-&amp;gt;arr('|');   // ['a', 'b']   &amp;lt;- already works&lt;/p&gt;
&lt;p&gt;Only methods callable with zero arguments would be eligible. 'abc'-&amp;gt;needsArg would throw ArgumentCountError. Unknown names keep today's behavior.&lt;/p&gt;
&lt;p&gt;Why this is cheap here: the main use case for scalar extension methods is derived values (length, upper, slug, toArray), which read like properties. And first-class callables are already disabled for scalar receivers (a by-value receiver cannot be bound into a Closure), so $s-&amp;gt;arr cannot be interpreted as &amp;quot;return a Closure&amp;quot; - the only remaining meaning is &amp;quot;call it and return the value&amp;quot;. That removes the usual ambiguity that makes this expensive in C#.&lt;/p&gt;
&lt;p&gt;Scope: scalar receivers only (string, int, float, bool, array). Object receivers are excluded on purpose: a missing property on an object is usually a typo, and turning that warning into a successful call would weaken a useful diagnostic. Scalars have no property table today, so nothing is shadowed.&lt;/p&gt;
&lt;p&gt;Backward compatibility: no parser change; -&amp;gt;name already compiles to ZEND_FETCH_OBJ_R. Today the affected expressions always emit &amp;quot;Warning: Attempt to read property &amp;quot;x&amp;quot; on string&amp;quot; and evaluate to null, which no correct code can rely on. Verified against a local build of hollyschilling/php-src@extension-methods-scalars (5e5112f):&lt;/p&gt;
&lt;p&gt;'aaa'-&amp;gt;length;   // Warning: Attempt to read property &amp;quot;length&amp;quot; on string -&amp;gt; &lt;code&gt;NULL&lt;/code&gt; &lt;br&gt;
'a,b'-&amp;gt;arr;      // Warning: Attempt to read property &amp;quot;arr&amp;quot; on string    -&amp;gt; &lt;code&gt;NULL&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;These two lines are exactly what the proposal would change.&lt;/p&gt;
&lt;p&gt;Open questions I'd like the list's input on:&lt;/p&gt;
&lt;p&gt;A. When a method has a required parameter, throw ArgumentCountError (my preference; a silent null would be indistinguishable from a typo), or fall back to the existing warning?&lt;/p&gt;
&lt;p&gt;B. Should isset() / ?? consult the registry, or stay untouched for v1?&lt;/p&gt;
&lt;p&gt;C. Is excluding object receivers the right call, or is the resulting inconsistency ($str-&amp;gt;upper works, $obj-&amp;gt;upper does not) worse than losing the typo diagnostic on objects?&lt;/p&gt;
&lt;p&gt;Happy to prototype against the extension-methods-scalars branch once (A) is settled.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
h4acda&lt;/p&gt;
&lt;p&gt;497161114 &lt;br&gt;
&lt;a href="mailto:h4acda@qq.com" rel="nofollow" target="_blank"&gt;h4acda@qq.com&lt;/a&gt;&lt;/p&gt;
</description><guid>tencent_FA2BAE27C04788DA132AFF479D26CCB22E06@qq.com</guid><pubDate>Sat, 24 Oct 2026 09:33:53 +0000</pubDate></item><item><title>[RFC] Paren-less access to scalar extension methods ('a,b'-&gt;arr as sugar for 'a,b'-&gt;arr())</title><link>https://externals.io/message/132912</link><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;This follows up on the Extension Methods / Scalar Extension Methods RFCs (currently in draft). I'd like to propose allowing extension methods on scalar values to be invoked through property-fetch syntax, with the parentheses omitted.&lt;/p&gt;
&lt;p&gt;Proposal: when a property read on a scalar fails, fall back to the extension method registry and invoke the method with its default arguments. -&amp;gt;name becomes sugar for -&amp;gt;name().&lt;/p&gt;
&lt;p&gt;Only methods callable with zero arguments would be eligible. 'abc'-&amp;gt;needsArg would throw ArgumentCountError. Unknown names keep today's behavior.&lt;/p&gt;
&lt;p&gt;Why this is cheap here: the main use case for scalar extension methods is derived values (length, upper, slug, toArray), which read like properties. And first-class callables are already disabled for scalar receivers (a by-value receiver cannot be bound into a Closure), so $s-&amp;gt;arr cannot be interpreted as &amp;quot;return a Closure&amp;quot; - the only remaining meaning is &amp;quot;call it and return the value&amp;quot;. That removes the usual ambiguity that makes this expensive in C#.&lt;/p&gt;
&lt;p&gt;Scope: scalar receivers only (string, int, float, bool, array). Object receivers are excluded on purpose: a missing property on an object is usually a typo, and turning that warning into a successful call would weaken a useful diagnostic. Scalars have no property table today, so nothing is shadowed.&lt;/p&gt;
&lt;p&gt;Backward compatibility: no parser change; -&amp;gt;name already compiles to ZEND_FETCH_OBJ_R. Today the affected expressions always emit &amp;quot;Warning: Attempt to read property &amp;quot;x&amp;quot; on string&amp;quot; and evaluate to null, which no correct code can rely on. Verified against a local build of hollyschilling/php-src@extension-methods-scalars (5e5112f):&lt;/p&gt;
&lt;p&gt;These two lines are exactly what the proposal would change.&lt;/p&gt;
&lt;p&gt;Open questions I'd like the list's input on:&lt;/p&gt;
&lt;p&gt;A. When a method has a required parameter, throw ArgumentCountError (my preference; a silent null would be indistinguishable from a typo), or fall back to the existing warning?&lt;/p&gt;
&lt;p&gt;B. Should isset() / ?? consult the registry, or stay untouched for v1?&lt;/p&gt;
&lt;p&gt;C. Is excluding object receivers the right call, or is the resulting inconsistency ($str-&amp;gt;upper works, $obj-&amp;gt;upper does not) worse than losing the typo diagnostic on objects?&lt;/p&gt;
&lt;p&gt;Happy to prototype against the extension-methods-scalars branch once (A) is settled.&lt;/p&gt;
&lt;p&gt;Thanks, &amp;lt;H4acda&amp;gt;&lt;/p&gt;
&lt;p&gt;497161114 &lt;br&gt;
&lt;a href="mailto:h4acda@qq.com" rel="nofollow" target="_blank"&gt;h4acda@qq.com&lt;/a&gt;&lt;/p&gt;
</description><guid>tencent_0A1D5662CFBA0F1F355854BA8F544DA76507@qq.com</guid><pubDate>Sat, 24 Oct 2026 09:26:17 +0000</pubDate></item><item><title>RFC karma request: array_partition()</title><link>https://externals.io/message/132911</link><description>&lt;blockquote&gt;
&lt;p&gt;Hi Ayoub,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It feels unintuitive that &lt;code&gt;true&lt;/code&gt; callback outcomes map to the &lt;code&gt;0&lt;/code&gt; key &lt;br&gt;
and &lt;code&gt;false&lt;/code&gt; outcomes map to &lt;code&gt;1&lt;/code&gt;. &lt;br&gt;
I'm also in support, and this would have been my only observation: my &lt;br&gt;
partition functions also map passes and rejects to true and false &lt;br&gt;
respectively (so the result is a mapping from booleans to array values).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;If that mapping were retained, it could be documented in code as&lt;/p&gt;
&lt;p&gt;[true =&amp;gt; $passed, false =&amp;gt; $rejected] = array_partition(...);&lt;/p&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;p&gt;$adult_tested = array_partition(...);&lt;/p&gt;
&lt;p&gt;$adults = $adult_tested[true]; &lt;br&gt;
$minors = $adult_tested[false];&lt;/p&gt;
&lt;p&gt;I would also prefer the callback parameter to be named $predicate, to &lt;br&gt;
emphasise that it is supposed to return a boolean. $callback doesn't &lt;br&gt;
convey as much about what it's for - the same name is used, for example, &lt;br&gt;
in &lt;code&gt;usort()&lt;/code&gt;, where it's a comparator. It didn't matter until named &lt;br&gt;
parameters became a thing.&lt;/p&gt;
</description><guid>942aeed7-1f7d-485d-8912-b78cb489689f@varteg.nz</guid><pubDate>Sat, 24 Oct 2026 04:46:28 +0000</pubDate></item><item><title>RFC karma request: array_partition()</title><link>https://externals.io/message/132910</link><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;Thanks for the support and the detailed feedback!&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Semantically, the function name affords an indefinite number of &lt;br&gt;
groups/partitions. &lt;br&gt;
[...]&lt;/li&gt;
&lt;li&gt;Was strictly partitioning into only two parts a deliberate intention &lt;br&gt;
specific to the term &amp;quot;partition&amp;quot;?&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, it was deliberate. In the languages and libraries PHP developers &lt;br&gt;
are most likely to know, &amp;quot;partition&amp;quot; means a split by a boolean &lt;br&gt;
predicate into exactly two parts: Ruby's Enumerable#partition, Kotlin's &lt;br&gt;
partition, Rust's Iterator::partition, Haskell's Data.List.partition and &lt;br&gt;
Laravel's Collection::partition. Each of them also ships grouping as a &lt;br&gt;
separate function (group_by, groupBy, ...). I'd like PHP to follow the &lt;br&gt;
same split, so that array_partition() does what people coming from &lt;br&gt;
those ecosystems expect.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;I want to be able to make unlimited groups keyed by the callback's &lt;br&gt;
return value&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's a useful function too, but I think it's a different one. There &lt;br&gt;
is an existing draft RFC for exactly that, array_group() by Boro &lt;br&gt;
Sitnikovski (&lt;a href="https://wiki.php.net/rfc/array_group" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/array_group&lt;/a&gt;, 2023), which never &lt;br&gt;
went to a vote. I'd be happy to see it revived, and the two would &lt;br&gt;
complement each other.&lt;/p&gt;
&lt;p&gt;Using a general grouping function for the two-way case is also less &lt;br&gt;
convenient: the bucket keys come from the callback's return value, and &lt;br&gt;
a bucket is missing entirely when nothing falls into it. You'd write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$groups = array_group($users, fn($u) =&amp;gt; $u-&amp;gt;age &amp;gt;= 18 ? 'adult' : 'minor');
$adults = $groups['adult'] ?? [];
$minors = $groups['minor'] ?? [];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;whereas array_partition() always returns both parts, so destructuring &lt;br&gt;
always works:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[$adults, $minors] = array_partition($users, fn($u) =&amp;gt; $u-&amp;gt;age &amp;gt;= 18);
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;It feels unintuitive that &lt;code&gt;true&lt;/code&gt; callback outcomes map to the &lt;code&gt;0&lt;/code&gt; key &lt;br&gt;
and &lt;code&gt;false&lt;/code&gt; outcomes map to &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;The result is meant to be read as a pair rather than a map from boolean &lt;br&gt;
to bucket, and &amp;quot;matching first&amp;quot; is the order used by all of the &lt;br&gt;
functions above. With destructuring, the names carry the meaning: &lt;br&gt;
[$matching, $rest].&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The callback should have access to the arrays keys and values.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Agreed, and this is already done: following review on the PR, the &lt;br&gt;
callback now receives ($value, $key), like &lt;code&gt;array_find()&lt;/code&gt; and friends, &lt;br&gt;
and the $mode parameter is gone:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function array_partition(array $array, callable $callback): array
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="https://github.com/php/php-src/pull/24568" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24568&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'll cover the naming and the relationship to array_group() in the RFC.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Ayoub&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi Ayoub,&lt;/p&gt;
&lt;p&gt;I am in support of &lt;code&gt;array_partition()&lt;/code&gt; being added to the language in some way. Here is my feedback:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Semantically, the function name affords an indefinite number of groups/partitions. I have had many use cases where more than two partitions are desired.&lt;/li&gt;
&lt;li&gt;It feels unintuitive that &lt;code&gt;true&lt;/code&gt; callback outcomes map to the &lt;code&gt;0&lt;/code&gt; key and &lt;code&gt;false&lt;/code&gt; outcomes map to &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I want to be able to make unlimited groups keyed by the callback's return value (so long as the return value is a string or an int). &lt;br&gt;
&lt;code&gt;$ageGrouped = array_partition($users, fn($u) =&amp;gt; $u-&amp;gt;age ?? -1);&lt;/code&gt; &lt;br&gt;
&lt;code&gt;$byFirstByte = array_partition($words, fn($word) =&amp;gt; substr($word, 0, 1));&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The callback should have access to the arrays keys and values. &lt;br&gt;
&lt;code&gt;$modulusGrouped = array_partition($rows, fn($row, $i) =&amp;gt; $i % 7);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Allowing your original intention of an indexed array with true outcomes first is still afforded by tweaking the evaluation or merely negating the boolean outcomes with &lt;code&gt;!(expression)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Was strictly partitioning into only two parts a deliberate intention specific to the the term &amp;quot;partition&amp;quot;? I mean, did you deliberately choose to not name the function &lt;code&gt;array_group()&lt;/code&gt;/&lt;code&gt;array_batch()&lt;/code&gt; which might align with my behavioral deviation?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Good luck with the RFC.&lt;/p&gt;
&lt;p&gt;mickmackusa&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CAB=6nSbhPdRa_KHcXg0A3r5j5n8r1X91CKj52WFgjVsbiaBTdQ@mail.gmail.com</guid><pubDate>Sat, 24 Oct 2026 00:19:33 +0000</pubDate></item><item><title>[RFC] Io\Terminal</title><link>https://externals.io/message/132909</link><description>&lt;p&gt;Hi Sjoerd,&lt;/p&gt;
&lt;p&gt;Thanks for taking a look.&lt;/p&gt;
&lt;p&gt;Perhaps it would be desirable to distinguish between the user cancelling, &lt;br&gt;
and a genuine error, and perhaps also EOF; for example with subclasses of &lt;br&gt;
TerminalException.&lt;/p&gt;
&lt;p&gt;Yes, I see the use case. An application may handle a cancelled password &lt;br&gt;
prompt quietly but report an I/O failure. Currently they all throw &lt;br&gt;
TerminalException, and the messages are not stable identifiers. Separate &lt;br&gt;
subclasses would allow that distinction while keeping TerminalException as &lt;br&gt;
the common catch. I would like to settle this before the vote.&lt;/p&gt;
&lt;p&gt;Is this sufficiently long, even when used over SSH or such? Is this &lt;br&gt;
configurable in readSecret as well?&lt;/p&gt;
&lt;p&gt;The 25 ms starts after Escape arrives, so it is not a limit on the SSH &lt;br&gt;
round trip. Delayed fragments can still exceed it. readKey() lets you &lt;br&gt;
increase sequenceTimeout, within the overall timeout.&lt;/p&gt;
&lt;p&gt;readSecret() currently uses a fixed 25 ms wait in its byte-stream escape &lt;br&gt;
handling. It is not separately configurable, and increasing the overall &lt;br&gt;
timeout does not increase that wait. That is a limitation worth addressing. &lt;br&gt;
Native Windows console input uses input records, so this escape-sequence &lt;br&gt;
timing does not apply there.&lt;/p&gt;
&lt;p&gt;If I resize the terminal twice, do I get two Key::Resize? getSize() seems &lt;br&gt;
to update the stored size of the terminal. Do I still get a Key::Resize &lt;br&gt;
after I call getSize()?&lt;/p&gt;
&lt;p&gt;Not necessarily two. On POSIX, resize notifications can be coalesced, and &lt;br&gt;
changes between reads can be detected by comparing dimensions.&lt;/p&gt;
&lt;p&gt;You are right about getSize(). It updates the same cached dimensions, so &lt;br&gt;
calling it first can hide a change from that comparison. Windows can still &lt;br&gt;
have queued resize records. I think getSize() should query the size without &lt;br&gt;
acknowledging a pending notification. That needs fixing and documenting. &lt;br&gt;
Resize should mean &amp;quot;check the current size&amp;quot;, rather than promise a count of &lt;br&gt;
every resize.&lt;/p&gt;
&lt;p&gt;This would not work with escape sequences, right? Or does it work correctly &lt;br&gt;
if the key is already buffered?&lt;/p&gt;
&lt;p&gt;Reading the current byte-stream decoder, the zero deadline makes it return &lt;br&gt;
Escape before checking the remaining bytes, even if the whole sequence is &lt;br&gt;
buffered. The focused zero-timeout test covers a lone Escape.&lt;/p&gt;
&lt;p&gt;Zero should prevent waiting while still allowing a complete available &lt;br&gt;
sequence to be decoded. That needs a focused regression test and a fix.&lt;/p&gt;
&lt;p&gt;I’ll follow up with the test results and changes. These findings are from &lt;br&gt;
checking the code; I haven’t run the new reproducers yet.&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Pratik&lt;/p&gt;
</description><guid>CA+9BsNf3QDZ3ExoLG1Twvsd0R+tXAYdJqq68ysxpG8yBGFnQpg@mail.gmail.com</guid><pubDate>Fri, 23 Oct 2026 23:44:51 +0000</pubDate></item><item><title>RFC karma request: array_partition()</title><link>https://externals.io/message/132908</link><description>&lt;p&gt;Hi Ayoub,&lt;/p&gt;
&lt;p&gt;I am in support of &lt;code&gt;array_partition()&lt;/code&gt; being added to the language in some &lt;br&gt;
way. Here is my feedback:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Semantically, the function name affords an indefinite number of &lt;br&gt;
groups/partitions. I have had many use cases where more than two partitions &lt;br&gt;
are desired.&lt;/li&gt;
&lt;li&gt;It feels unintuitive that &lt;code&gt;true&lt;/code&gt; callback outcomes map to the &lt;code&gt;0&lt;/code&gt; key and &lt;br&gt;
&lt;code&gt;false&lt;/code&gt; outcomes map to &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I want to be able to make unlimited groups keyed by the callback's return &lt;br&gt;
value (so long as the return value is a string or an int). &lt;br&gt;
&lt;code&gt;$ageGrouped = array_partition($users, fn($u) =&amp;gt; $u-&amp;gt;age ?? -1);&lt;/code&gt; &lt;br&gt;
&lt;code&gt;$byFirstByte = array_partition($words, fn($word) =&amp;gt; substr($word, 0, 1));&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The callback should have access to the arrays keys and values. &lt;br&gt;
&lt;code&gt;$modulusGrouped = array_partition($rows, fn($row, $i) =&amp;gt; $i % 7);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Allowing your original intention of an indexed array with true outcomes &lt;br&gt;
first is still afforded by tweaking the evaluation or merely negating the &lt;br&gt;
boolean outcomes with &lt;code&gt;!(expression)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Was strictly partitioning into only two parts a deliberate intention &lt;br&gt;
specific to the the term &amp;quot;partition&amp;quot;? I mean, did you deliberately choose &lt;br&gt;
to not name the function &lt;code&gt;array_group()&lt;/code&gt;/&lt;code&gt;array_batch()&lt;/code&gt; which might align &lt;br&gt;
with my behavioral deviation?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Good luck with the RFC.&lt;/p&gt;
&lt;p&gt;mickmackusa&lt;/p&gt;
</description><guid>CAKVXxD9ZWXTStvMh5rTdGRJUi2ViGV=o6f-aOCMgm=6K2O_Kgg@mail.gmail.com</guid><pubDate>Fri, 23 Oct 2026 23:16:27 +0000</pubDate></item><item><title>[IDEA] Native async/await syntax on top of Fibers</title><link>https://externals.io/message/132907</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to gauge interest in adding native async/await syntax to PHP, &lt;br&gt;
built on top of the Fiber implementation we've had since 8.1.&lt;/p&gt;
&lt;p&gt;Fibers made it possible to write concurrent code without &amp;quot;function &lt;br&gt;
colouring&amp;quot;, but in practice everyone still picks a userland library &lt;br&gt;
(Amp, ReactPHP, Revolt) together with its own Promise/Future type, and &lt;br&gt;
the code doesn't say directly what it means. The idea is to give the &lt;br&gt;
engine a small, standard vocabulary for this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function fetch(string $name, float $secs): string {
    await Async\delay($secs);
    return &amp;quot;$name done&amp;quot;;
}

$a = fetch(&amp;quot;a&amp;quot;, 0.2);   // starts right away, returns Async\Future
$b = fetch(&amp;quot;b&amp;quot;, 0.2);
echo await $a, await $b; // ~0.2s total, not 0.4s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Proposed semantics, in short:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;async&lt;/code&gt; can be applied to functions, methods, closures and arrow &lt;br&gt;
functions. Calling one runs its body in a new Fiber and returns an &lt;br&gt;
Async\Future. The task starts eagerly and runs until it awaits a &lt;br&gt;
Future that isn't complete yet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;await &amp;lt;expr&amp;gt;&lt;/code&gt; inside a task suspends that task. Outside a task (at &lt;br&gt;
the top level, or in a plain Fiber) it drives a small scheduler until &lt;br&gt;
the Future completes. It returns the value or rethrows the exception.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;async&lt;/code&gt; is a contextual keyword: it is only a keyword when followed &lt;br&gt;
by &lt;code&gt;function&lt;/code&gt; or &lt;code&gt;fn&lt;/code&gt;, so existing userland async() functions keep &lt;br&gt;
working. &lt;code&gt;await&lt;/code&gt; would become a reserved keyword, though it remains &lt;br&gt;
usable as a method, constant or property name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tasks still pending at shutdown are destroyed the same way suspended &lt;br&gt;
Fibers are, so their finally blocks run. Deadlocks throw an Error &lt;br&gt;
instead of hanging.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A minimal runtime API: final class Async\Future, Async\async(), &lt;br&gt;
Async\wait() (the function form of await), Async\delay() and &lt;br&gt;
Async\suspend().&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have a working prototype. Both constructs are desugared in the &lt;br&gt;
parser into calls to the runtime functions, so there are no new opcodes &lt;br&gt;
and no VM changes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;a href="https://github.com/php/php-src/pull/24623" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24623&lt;/a&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It comes with tests and passes the existing test suite on a debug &lt;br&gt;
build (macOS arm64, NTS). I haven't tried it on Windows or ZTS yet.&lt;/p&gt;
&lt;p&gt;Questions I'd especially like feedback on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Is reserving &lt;code&gt;await&lt;/code&gt; an acceptable BC break? Unqualified functions &lt;br&gt;
named await() would break; namespaced calls such as &lt;br&gt;
Amp\Future\await() would not.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How should this relate to the True Async RFC? Should syntax like &lt;br&gt;
this be layered on top of that work rather than proposed separately?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What should I/O integration look like? The prototype only supports &lt;br&gt;
timers and cooperative yielding. Real-world usefulness depends on &lt;br&gt;
an event-loop or reactor story for streams and sockets.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Known rough edges in the desugaring approach: &lt;code&gt;func_get_args()&lt;/code&gt; inside &lt;br&gt;
an async body returns [], stack traces show an extra {closure} frame, &lt;br&gt;
and reflection reports the return type as Async\Future. Are these &lt;br&gt;
acceptable, or is a dedicated engine-level implementation preferred?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If there is interest, I'm happy to turn this into a proper RFC.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Abbas Al-Khateeb&lt;/p&gt;
</description><guid>CAB0Y74ygGH7qB-D_f6UsDv93XqGWU86E2tYwbRTnWry04zUuqg@mail.gmail.com</guid><pubDate>Fri, 23 Oct 2026 20:37:36 +0000</pubDate></item><item><title>[RFC] Io\Terminal</title><link>https://externals.io/message/132906</link><description>&lt;blockquote&gt;
&lt;p&gt;I would like to formally propose the Io\Terminal API for PHP 8.7:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/io_terminal" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/io_terminal&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Thank you. Nice work.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;EOF before submission, cancellation, and operational failures throw &lt;code&gt;TerminalException&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perhaps it would be desirable to distinguish between the user cancelling, and a genuine error, and perhaps also EOF; for example with subclasses of TerminalException.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The default for a blocking read is 25 milliseconds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Is this sufficiently long, even when used over SSH or such? Is this configurable in readSecret as well?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A resize is returned as &lt;code&gt;Key::Resize&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If I resize the terminal twice, do I get two Key::Resize? getSize() seems to update the stored size of the terminal. Do I still get a Key::Resize after I call getSize()?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$timeout sets the overall timeout: zero: make a non-blocking attempt&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This would not work with escape sequences, right? Or does it work correctly if the key is already buffered?&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
</description><guid>6202fefa-6fc5-4275-af05-ddf6000706f0@app.fastmail.com</guid><pubDate>Fri, 23 Oct 2026 20:26:19 +0000</pubDate></item><item><title>[Proposal] Clarifying the distinction between "PHP the Language" and "PHP the Software" on php.net</title><link>https://externals.io/message/132905</link><description>&lt;p&gt;Hi everyone,&lt;/p&gt;
&lt;p&gt;I would like to propose a small but important improvement regarding how PHP is described on the official &lt;a href="http://php.net" rel="nofollow" target="_blank"&gt;php.net&lt;/a&gt; website and documentation.&lt;/p&gt;
&lt;p&gt;Currently, many sections of the website simply use the term &amp;quot;PHP&amp;quot; without clearly distinguishing between &amp;quot;PHP as a programming language (the specification/syntax)&amp;quot; and &amp;quot;PHP as a software application (the official runtime environment/interpreter)&amp;quot;.&lt;/p&gt;
&lt;p&gt;This ambiguity causes significant confusion, particularly when users read about licensing. For example, statements implying that &amp;quot;PHP is available under the PHP License v4 / Modified BSD&amp;quot; can lead users—and corporate legal departments—to mistakenly believe that the license imposes restrictions or source-code disclosure requirements on the code they write in the PHP language itself.&lt;/p&gt;
&lt;p&gt;To prevent this confusion, I propose that we update the official website and documentation to be more precise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &amp;quot;PHP language&amp;quot; when referring to the syntax and coding rules.&lt;/li&gt;
&lt;li&gt;Use &amp;quot;PHP software&amp;quot; or &amp;quot;PHP engine&amp;quot; when referring to the official runtime and its distribution license.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A clearer distinction would greatly help newcomers, developers, and legal teams understand that the permissive license applies strictly to the runtime engine and does not restrict their proprietary user code.&lt;/p&gt;
&lt;p&gt;I would love to hear your thoughts on this.&lt;/p&gt;
&lt;p&gt;Best regards, &lt;br&gt;
The_PHP_Distinction&lt;/p&gt;
</description><guid>1314567156.273819.1792784987010@mail.yahoo.co.jp</guid><pubDate>Fri, 23 Oct 2026 19:49:46 +0000</pubDate></item><item><title>PHP 8.4.27 configure writes to read-only source tree but exits successfully</title><link>https://externals.io/message/132904</link><description>&lt;p&gt;Kangwa Mukonda &lt;a href="mailto:mukondakangwa1@gmail.com"&gt;mukondakangwa1@gmail.com&lt;/a&gt; &lt;br&gt;
11:44 AM (5 minutes ago)&lt;/p&gt;
&lt;p&gt;to internals &lt;br&gt;
Hello PHP internals,&lt;/p&gt;
&lt;p&gt;I found a reproducible out-of-tree build-system issue in the signed PHP &lt;br&gt;
8.4.27 release. I am using the internals list because &lt;a href="http://bugs.php.net" rel="nofollow" target="_blank"&gt;bugs.php.net&lt;/a&gt; no &lt;br&gt;
longer accepts reports and GitHub is unavailable in this environment.&lt;/p&gt;
&lt;p&gt;Summary&lt;/p&gt;
&lt;p&gt;When configure is run out of tree with the authenticated PHP source mounted &lt;br&gt;
read-only, it attempts to create main/php_config.h.in.tmp inside the source &lt;br&gt;
tree. The write fails with &amp;quot;Read-only file system&amp;quot;, but configure &lt;br&gt;
continues, creates the build Makefile, prints its success banner, and exits &lt;br&gt;
with status 0.&lt;/p&gt;
&lt;p&gt;Source&lt;/p&gt;
&lt;p&gt;PHP 8.4.27 official tar.xz &lt;br&gt;
SHA-256: dcf93923b0e38e0d5252b25b796520b5a47761a08b3488b6d0b5d1115764d3f0 &lt;br&gt;
Signature verified with PHP 8.4 release-manager key &lt;br&gt;
9D7F99A0CB8F05C8A6958D6256A97AF7600A39A6. &lt;br&gt;
The archive also matched Debian's independently signed php8.4 &lt;br&gt;
8.4.27-1~deb13u1 source byte-for-byte.&lt;/p&gt;
&lt;p&gt;Environment&lt;/p&gt;
&lt;p&gt;Kali rolling, x86_64 &lt;br&gt;
Linux 7.1.5+kali-amd64 &lt;br&gt;
GCC 15.3.0 &lt;br&gt;
GNU Make 4.4.1 &lt;br&gt;
Bubblewrap with a new network namespace; system and source trees read-only; &lt;br&gt;
out-of-tree build directory writable.&lt;/p&gt;
&lt;p&gt;Minimal reproduction&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Extract php-8.4.27.tar.xz.&lt;/li&gt;
&lt;li&gt;Create a separate writable build directory.&lt;/li&gt;
&lt;li&gt;Make or mount the source tree read-only.&lt;/li&gt;
&lt;li&gt;From the build directory run:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;/path/to/php-8.4.27/configure --disable-all --enable-cli --disable-cgi &lt;br&gt;
--disable-phpdbg --without-pear&lt;/p&gt;
&lt;p&gt;Observed result&lt;/p&gt;
&lt;p&gt;configure exit status: 0 &lt;br&gt;
Makefile created: yes &lt;br&gt;
success banner printed: yes &lt;br&gt;
read-only write failure count: 1&lt;/p&gt;
&lt;p&gt;Relevant output:&lt;/p&gt;
&lt;p&gt;configure: creating Makefile &lt;br&gt;
configure: patching main/php_&lt;a href="http://config.h.in" rel="nofollow" target="_blank"&gt;config.h.in&lt;/a&gt; &lt;br&gt;
/path/to/php-8.4.27/configure: line 93943: &lt;br&gt;
/path/to/php-8.4.27/main/php_config.h.in.tmp: Read-only file system &lt;br&gt;
Thank you for using PHP.&lt;/p&gt;
&lt;p&gt;Expected result&lt;/p&gt;
&lt;p&gt;For a supported out-of-tree configuration, configure should not modify the &lt;br&gt;
source tree. If modification is unavoidable, the failed write should be &lt;br&gt;
fatal and configure should return a nonzero status instead of reporting &lt;br&gt;
success.&lt;/p&gt;
&lt;p&gt;Additional result&lt;/p&gt;
&lt;p&gt;The generated build subsequently compiled successfully, so this report &lt;br&gt;
concerns the unexpected source-tree write and swallowed failure rather than &lt;br&gt;
a compilation failure.&lt;/p&gt;
&lt;p&gt;Evidence&lt;/p&gt;
&lt;p&gt;Full configure log SHA-256: &lt;br&gt;
860f4189fb5c1b9b3a3aae43ff8ad498cbab6bbd4582d7c9e6a40beb71fe11f5&lt;/p&gt;
&lt;p&gt;No exploit was developed or executed. I can provide the complete configure &lt;br&gt;
log and reproduction receipt if useful.&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Mukonda Kangwa &lt;br&gt;
Email: &lt;a href="mailto:mukondakangwa1@gmail.com" rel="nofollow" target="_blank"&gt;mukondakangwa1@gmail.com&lt;/a&gt; &lt;br&gt;
Phone / Airtel: +260 773 695 472 &lt;br&gt;
Lusaka, Zambia&lt;/p&gt;
</description><guid>CADHZxgtmGtdKgDd_zGup4a3MHxqk1QYCOCao9xLKOfr6S1vrXQ@mail.gmail.com</guid><pubDate>Fri, 23 Oct 2026 09:51:56 +0000</pubDate></item><item><title>[Meta] This Week In PHP Internals | October 22, 2026</title><link>https://externals.io/message/132903</link><description>&lt;p&gt;Hi Contributors,&lt;/p&gt;
&lt;p&gt;This week's episode is out, and it covers two weeks, since the October 15 &lt;br&gt;
episode never got recorded (I was in Austin for LonghornPHP, and all &lt;br&gt;
my time went towards polishing my talk instead of working on the &lt;br&gt;
video). Here's the video, plus everywhere else it landed &lt;br&gt;
for visibility.&lt;/p&gt;
&lt;p&gt;Same invitation as always: if I got something wrong, reply in this thread and &lt;br&gt;
I'll make corrections. That includes how I'm pronouncing your names.&lt;/p&gt;
&lt;p&gt;If you'd rather read than watch, the &lt;a href="http://dev.to" rel="nofollow" target="_blank"&gt;dev.to&lt;/a&gt; post carries the full episode as &lt;br&gt;
an article, which also makes it the easiest version to quote when correcting &lt;br&gt;
me: &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-oct-22-2026-ii8" rel="nofollow" target="_blank"&gt;https://dev.to/projektgopher/this-week-in-php-internals-oct-22-2026-ii8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;youtube &lt;a href="https://youtu.be/4ze2Re_-gMQ" rel="nofollow" target="_blank"&gt;https://youtu.be/4ze2Re_-gMQ&lt;/a&gt; &lt;br&gt;
&lt;a href="http://dev.to" rel="nofollow" target="_blank"&gt;dev.to&lt;/a&gt; &lt;a href="https://dev.to/projektgopher/this-week-in-php-internals-oct-22-2026-ii8" rel="nofollow" target="_blank"&gt;https://dev.to/projektgopher/this-week-in-php-internals-oct-22-2026-ii8&lt;/a&gt; &lt;br&gt;
mastodon &lt;a href="https://phpc.social/@ProjektGopher/117487634385670894" rel="nofollow" target="_blank"&gt;https://phpc.social/@ProjektGopher/117487634385670894&lt;/a&gt; &lt;br&gt;
threads &lt;a href="https://www.threads.com/@projektgopher/post/De0Y_rYGpBG" rel="nofollow" target="_blank"&gt;https://www.threads.com/@projektgopher/post/De0Y_rYGpBG&lt;/a&gt; &lt;br&gt;
bsky &lt;a href="https://bsky.app/profile/projektgopher.com/post/3myizo6lprs2e" rel="nofollow" target="_blank"&gt;https://bsky.app/profile/projektgopher.com/post/3myizo6lprs2e&lt;/a&gt; &lt;br&gt;
twitter &lt;a href="https://x.com/ProjektGopher/status/2113438312572817588" rel="nofollow" target="_blank"&gt;https://x.com/ProjektGopher/status/2113438312572817588&lt;/a&gt; &lt;br&gt;
linkedin &lt;a href="https://www.linkedin.com/feed/update/urn:li:ugcPost:7519206561148420096/" rel="nofollow" target="_blank"&gt;https://www.linkedin.com/feed/update/urn:li:ugcPost:7519206561148420096/&lt;/a&gt; &lt;br&gt;
pinkary &lt;a href="https://pinkary.com/@ProjektGopher/questions/01a16669-04c3-710b-bd17-acbedc8ac5a6" rel="nofollow" target="_blank"&gt;https://pinkary.com/@ProjektGopher/questions/01a16669-04c3-710b-bd17-acbedc8ac5a6&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cheers, &lt;br&gt;
Len&lt;/p&gt;
</description><guid>CAEwAiAHDqmBuC5su1U=0JAHxHysdNtkJvFR0irfNakkt9uHbUQ@mail.gmail.com</guid><pubDate>Fri, 23 Oct 2026 02:00:06 +0000</pubDate></item><item><title>RFC karma request: array_partition()</title><link>https://externals.io/message/132902</link><description>&lt;p&gt;Hi internals,&lt;/p&gt;
&lt;p&gt;I'd like to request RFC karma on the wiki to propose a new function, &lt;br&gt;
array_partition(). My wiki username is: ayoubezzini&lt;/p&gt;
&lt;p&gt;The function splits an array into the elements that satisfy a callback &lt;br&gt;
and those that don't, in a single pass:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[$adults, $minors] = array_partition($users, fn($u) =&amp;gt; $u-&amp;gt;age &amp;gt;= 18);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It returns [$matching, $nonMatching], preserves keys, and takes the same &lt;br&gt;
$mode argument (ARRAY_FILTER_USE_KEY / ARRAY_FILTER_USE_BOTH) as &lt;br&gt;
&lt;code&gt;array_filter()&lt;/code&gt;. Today the same result needs two &lt;code&gt;array_filter()&lt;/code&gt; passes &lt;br&gt;
with a negated callback, or &lt;code&gt;array_filter()&lt;/code&gt; followed by &lt;code&gt;array_diff_key()&lt;/code&gt;. &lt;br&gt;
The same operation exists as Laravel's Collection::partition(), Ruby's &lt;br&gt;
Enumerable#partition, Kotlin's partition and Rust's Iterator::partition.&lt;/p&gt;
&lt;p&gt;An implementation with tests is available as a draft PR: &lt;br&gt;
&lt;a href="https://github.com/php/php-src/pull/24568" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/24568&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I'll open the formal [RFC] discussion thread once the wiki page is up.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Ayoub Ezzini&lt;/p&gt;
</description><guid>CAB=6nSZ+-drPD0r6UsSC8zf8g5W7BK=9G=Ep7H8pDm5EX9m32A@mail.gmail.com</guid><pubDate>Thu, 22 Oct 2026 18:50:19 +0000</pubDate></item><item><title>SSRF protection in curl</title><link>https://externals.io/message/132901</link><description>&lt;p&gt;Is there any reason we should intentionally make this curl specific? &lt;br&gt;
Meaning, we could design support for making it work for streams as &lt;br&gt;
well, couldn't we? Why make a curl specific feature instead of a &lt;br&gt;
language wide one?&lt;/p&gt;
</description><guid>CAAKU0ukkH2s6NL5SCjS_5A=8a7eOoRqxUKJY9ofL7knwtjLfrA@mail.gmail.com</guid><pubDate>Thu, 22 Oct 2026 14:58:25 +0000</pubDate></item><item><title>SSRF protection in curl</title><link>https://externals.io/message/132900</link><description>&lt;p&gt;Thanks Nicolas for your message, good to see some traction around the idea. &lt;br&gt;
Before working on the next step; i would love to hear from bukka - he had &lt;br&gt;
some concerns about the api so we makes sure it may be extended.&lt;/p&gt;
&lt;p&gt;I would appreciate it if we may discuss the specifics here before I move &lt;br&gt;
forward with a new PR and an RFC.&lt;/p&gt;
&lt;p&gt;Have a nice day,&lt;/p&gt;
&lt;p&gt;Xavier&lt;/p&gt;
&lt;p&gt;Le jeu. 22 oct. 2026 à 09:14, Nicolas Grekas &lt;a href="mailto:nicolas.grekas+php@gmail.com"&gt;nicolas.grekas+php@gmail.com&lt;/a&gt; &lt;br&gt;
a écrit :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le jeu. 15 oct. 2026 à 11:10, Xavier Leune &amp;lt; &lt;br&gt;
&lt;a href="mailto:xavier.leune+internals@gmail.com" rel="nofollow" target="_blank"&gt;xavier.leune+internals@gmail.com&lt;/a&gt;&amp;gt; a écrit :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi Sjoerd,&lt;/p&gt;
&lt;p&gt;Thanks for reopening this discussion ! I planned to do it in the &lt;br&gt;
coming days too, I'm really eager to see this land in PHP :) &lt;br&gt;
I'm pretty open about the 2 ways to implement it, however the discussion &lt;br&gt;
on 23657 about 22159 suggested a socket class bound to curl only, to make &lt;br&gt;
things easier to manage and to remove the dependency to ext/socket.&lt;/p&gt;
&lt;p&gt;In my opinion, CURLOPT_OPENSOCKETFUNCTION with the boolean may be a good &lt;br&gt;
idea. I'm not sure there is a real use case to open a wider support in PHP&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this option exists for almost 2 decades and I'm not sure anyone needed it. &lt;br&gt;
For the record I plan to implement the feature in a polyfill extension - &lt;br&gt;
with the same approach that we'll retain for PHP, to offer support in lower &lt;br&gt;
php versions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are a lot of small details we can discuss if we retain the &lt;br&gt;
OPENSOCKET_FUNCTION: the signature may be expanded to offer the same level &lt;br&gt;
of data as curl offers &lt;br&gt;
&lt;a href="https://curl.se/libcurl/c/CURLOPT_OPENSOCKETFUNCTION.html"&gt;https://curl.se/libcurl/c/CURLOPT_OPENSOCKETFUNCTION.html&lt;/a&gt;. This would &lt;br&gt;
make things easier if we want to support a full &lt;code&gt;CurlSocket&lt;/code&gt; object later.&lt;/p&gt;
&lt;p&gt;There is a first draft here: &lt;br&gt;
&lt;a href="https://github.com/xavierleune/curl-hardening" rel="nofollow" target="_blank"&gt;https://github.com/xavierleune/curl-hardening&lt;/a&gt; &lt;br&gt;
My idea was to use this extension as a sandbox before pushing a new &lt;br&gt;
discussion here, I will follow the API we may agree on for PHP 8.7.&lt;/p&gt;
&lt;p&gt;I think the approach in the current extension may address the concerns &lt;br&gt;
expressed by Bukka on 22159, while giving room to expand the support later.&lt;/p&gt;
&lt;p&gt;Do you think this approach is worth pursuing ?&lt;/p&gt;
&lt;p&gt;Thanks,&lt;/p&gt;
&lt;p&gt;Xavier&lt;/p&gt;
&lt;p&gt;Le jeu. 15 oct. 2026 à 10:48, Sjoerd Langkemper &lt;a href="mailto:sjoerd-php@linuxonly.nl"&gt;sjoerd-php@linuxonly.nl&lt;/a&gt; &lt;br&gt;
a écrit :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If an application performs HTTP requests based on user input, it is &lt;br&gt;
often desirable to verify that the connection is done to an allowed host. &lt;br&gt;
Otherwise the functionality could be abused to request resources on the &lt;br&gt;
server or on the same network as the server (SSRF).&lt;/p&gt;
&lt;p&gt;Xavier Leune made some pull requests to make this possible in curl. The &lt;br&gt;
idea is to hook in a callback that can verify the IP address that curl is &lt;br&gt;
going to connect to.&lt;/p&gt;
&lt;p&gt;22159: exposes callbacks such as CURLOPT_OPENSOCKETFUNCTION. These are &lt;br&gt;
supported by curl, but exposing the socket to userland comes with problems. &lt;br&gt;
23657: introduces CURLOPT_PRECONNECTFUNCTION. This is not supported by &lt;br&gt;
curl and is PHP-only, deviating from the normally thin abstraction on top &lt;br&gt;
of curl.&lt;/p&gt;
&lt;p&gt;The current plan is to expose only CURLOPT_OPENSOCKETFUNCTION with the &lt;br&gt;
signature function(string $address, int $port): bool. This is pretty &lt;br&gt;
limited compared with what OPENSOCKETFUNCTION can normally do, but at &lt;br&gt;
least makes it possible to do SSRF protection.&lt;/p&gt;
&lt;p&gt;What do you think? How can we expose SSRF protection to applications &lt;br&gt;
that perform curl requests?&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, please make this happen! But don't introduce CURLOPT_PRECONNECTFUNCTION&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a CURLOPT_OPENSOCKETFUNCTION bound to the simpler callback that returns &lt;br&gt;
a bool look enough. &lt;br&gt;
I'd use it it Symfony's CurlHttpClient, to replace the blocking call to &lt;br&gt;
the DNS that we have to do today. &lt;br&gt;
It would also be a useful primitive to hack around the blocking DNS we &lt;br&gt;
have to use at the moment - I would build an async DNS resolver out of this &lt;br&gt;
:)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cheers, &lt;br&gt;
Nicolas&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>CAKNL=Fet5_pfQfUMz0zajYN02KwpvX54yKwds2Ygq09LuR3t6w@mail.gmail.com</guid><pubDate>Thu, 22 Oct 2026 14:26:57 +0000</pubDate></item><item><title>[RFC] Pattern Matching — missing keys and strict int</title><link>https://externals.io/message/132899</link><description>&lt;blockquote&gt;
&lt;p&gt;Hello Larry and Ilija,&lt;/p&gt;
&lt;p&gt;I maintain a production PHP application that rejects a model’s JSON reply unless every field is present and of an exact type. Pattern matching is the language feature that would replace those checks. Two outcomes in the current draft would make that replacement accept replies we currently reject. Both are constraints on the rules you already wrote, not requests for new syntax.&lt;/p&gt;
&lt;p&gt;The RFC’s array-pattern equivalents use &lt;code&gt;array_key_exists()&lt;/code&gt; before comparing the value. A missing key therefore fails the pattern. The implementation note on &lt;a href="https://github.com/php/php-src/pull/20574" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/pull/20574&lt;/a&gt; says the draft reads a missing element as null, so this is true:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;['a' =&amp;gt; 42] is ['b' =&amp;gt; null]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Please keep the RFC text. For this parser, a missing key and an explicit null are different successful results, and a value of any other type is a failure:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function partQuote(array $p): ?array {
    if (!is_string($p['part'] ?? null)) {
        return null;
    }
    if (array_key_exists('quote', $p) &amp;amp;&amp;amp; $p['quote'] !== null &amp;amp;&amp;amp; !is_string($p['quote'])) {
        return null;
    }
    $out = ['part' =&amp;gt; $p['part']];
    if (array_key_exists('quote', $p)) {
        $out['quote'] = $p['quote']; // null is kept; the key was present
    }
    return $out;
}

partQuote(['part' =&amp;gt; 'A']);                    // ['part' =&amp;gt; 'A']
partQuote(['part' =&amp;gt; 'A', 'quote' =&amp;gt; null]);   // ['part' =&amp;gt; 'A', 'quote' =&amp;gt; null]
partQuote(['part' =&amp;gt; 'A', 'quote' =&amp;gt; 1]);      // null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If ['quote' =&amp;gt; null] matched a missing quote, the first two calls would become the same pattern and the stored shape would be wrong.&lt;/p&gt;
&lt;p&gt;The same parser requires a real int for a score-like field, in 0..100 inclusive. &lt;code&gt;is_int()&lt;/code&gt; is the type check; the range is applied only after that. These all fail:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;['strength' =&amp;gt; '80']
['strength' =&amp;gt; 80.0]
['strength' =&amp;gt; 101]
['relevant' =&amp;gt; 1]       // `is_bool()`, same rule: no coercion
['relevant' =&amp;gt; 'true']
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and ['strength' =&amp;gt; 80] with ['relevant' =&amp;gt; true] passes. An int pattern therefore has to reject a numeric string and a float. A range pattern such as &amp;gt;=0 &amp;amp; &amp;lt;=100 has to do the same when it is standing in for that field; &amp;quot;80&amp;quot; and 80.0 are inside the numeric range and are still the wrong type.&lt;/p&gt;
&lt;p&gt;I am not asking for a change to the feature set. The written array patterns already say &lt;code&gt;array_key_exists()&lt;/code&gt;, and an int pattern that follows &lt;code&gt;is_int()&lt;/code&gt; is what this code can adopt.&lt;/p&gt;
&lt;p&gt;Kevin Lopez&lt;/p&gt;
&lt;/blockquote&gt;
</description><guid>79BD0BED-73BA-4DDD-9423-D568EB07874A@gmail.com</guid><pubDate>Thu, 22 Oct 2026 12:30:14 +0000</pubDate></item><item><title>SSRF protection in curl</title><link>https://externals.io/message/132898</link><description>&lt;p&gt;Le jeu. 15 oct. 2026 à 11:10, Xavier Leune &lt;a href="mailto:xavier.leune+internals@gmail.com"&gt;xavier.leune+internals@gmail.com&lt;/a&gt; &lt;br&gt;
a écrit :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi Sjoerd,&lt;/p&gt;
&lt;p&gt;Thanks for reopening this discussion ! I planned to do it in the &lt;br&gt;
coming days too, I'm really eager to see this land in PHP :) &lt;br&gt;
I'm pretty open about the 2 ways to implement it, however the discussion &lt;br&gt;
on 23657 about 22159 suggested a socket class bound to curl only, to make &lt;br&gt;
things easier to manage and to remove the dependency to ext/socket.&lt;/p&gt;
&lt;p&gt;In my opinion, CURLOPT_OPENSOCKETFUNCTION with the boolean may be a good &lt;br&gt;
idea. I'm not sure there is a real use case to open a wider support in PHP&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this option exists for almost 2 decades and I'm not sure anyone needed it. &lt;br&gt;
For the record I plan to implement the feature in a polyfill extension - &lt;br&gt;
with the same approach that we'll retain for PHP, to offer support in lower &lt;br&gt;
php versions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are a lot of small details we can discuss if we retain the &lt;br&gt;
OPENSOCKET_FUNCTION: the signature may be expanded to offer the same level &lt;br&gt;
of data as curl offers &lt;br&gt;
&lt;a href="https://curl.se/libcurl/c/CURLOPT_OPENSOCKETFUNCTION.html"&gt;https://curl.se/libcurl/c/CURLOPT_OPENSOCKETFUNCTION.html&lt;/a&gt;. This would &lt;br&gt;
make things easier if we want to support a full &lt;code&gt;CurlSocket&lt;/code&gt; object later.&lt;/p&gt;
&lt;p&gt;There is a first draft here: &lt;a href="https://github.com/xavierleune/curl-hardening" rel="nofollow" target="_blank"&gt;https://github.com/xavierleune/curl-hardening&lt;/a&gt; &lt;br&gt;
My idea was to use this extension as a sandbox before pushing a new &lt;br&gt;
discussion here, I will follow the API we may agree on for PHP 8.7.&lt;/p&gt;
&lt;p&gt;I think the approach in the current extension may address the concerns &lt;br&gt;
expressed by Bukka on 22159, while giving room to expand the support later.&lt;/p&gt;
&lt;p&gt;Do you think this approach is worth pursuing ?&lt;/p&gt;
&lt;p&gt;Thanks,&lt;/p&gt;
&lt;p&gt;Xavier&lt;/p&gt;
&lt;p&gt;Le jeu. 15 oct. 2026 à 10:48, Sjoerd Langkemper &lt;a href="mailto:sjoerd-php@linuxonly.nl"&gt;sjoerd-php@linuxonly.nl&lt;/a&gt; &lt;br&gt;
a écrit :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If an application performs HTTP requests based on user input, it is often &lt;br&gt;
desirable to verify that the connection is done to an allowed host. &lt;br&gt;
Otherwise the functionality could be abused to request resources on the &lt;br&gt;
server or on the same network as the server (SSRF).&lt;/p&gt;
&lt;p&gt;Xavier Leune made some pull requests to make this possible in curl. The &lt;br&gt;
idea is to hook in a callback that can verify the IP address that curl is &lt;br&gt;
going to connect to.&lt;/p&gt;
&lt;p&gt;22159: exposes callbacks such as CURLOPT_OPENSOCKETFUNCTION. These are &lt;br&gt;
supported by curl, but exposing the socket to userland comes with problems. &lt;br&gt;
23657: introduces CURLOPT_PRECONNECTFUNCTION. This is not supported by &lt;br&gt;
curl and is PHP-only, deviating from the normally thin abstraction on top &lt;br&gt;
of curl.&lt;/p&gt;
&lt;p&gt;The current plan is to expose only CURLOPT_OPENSOCKETFUNCTION with the &lt;br&gt;
signature function(string $address, int $port): bool. This is pretty &lt;br&gt;
limited compared with what OPENSOCKETFUNCTION can normally do, but at &lt;br&gt;
least makes it possible to do SSRF protection.&lt;/p&gt;
&lt;p&gt;What do you think? How can we expose SSRF protection to applications that &lt;br&gt;
perform curl requests?&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd Langkemper&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, please make this happen! But don't introduce CURLOPT_PRECONNECTFUNCTION&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a CURLOPT_OPENSOCKETFUNCTION bound to the simpler callback that returns a &lt;br&gt;
bool look enough. &lt;br&gt;
I'd use it it Symfony's CurlHttpClient, to replace the blocking call to the &lt;br&gt;
DNS that we have to do today. &lt;br&gt;
It would also be a useful primitive to hack around the blocking DNS we have &lt;br&gt;
to use at the moment - I would build an async DNS resolver out of this :)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cheers, &lt;br&gt;
Nicolas&lt;/p&gt;
</description><guid>CAOWwgpkUm0F-TVhVX7LNK==xZq4Xqbfraffx+ev3D0hiPkFAGw@mail.gmail.com</guid><pubDate>Thu, 22 Oct 2026 08:14:35 +0000</pubDate></item><item><title>[VOTE] [RFC] IntlRelativeDateTimeFormatter</title><link>https://externals.io/message/132897</link><description>&lt;p&gt;Hello,&lt;/p&gt;
&lt;p&gt;The voting process of the IntlRelativeDateTimeFormatter RFC &lt;a href="%C2%A0https://wiki.php.net/rfc/reldateformatter"&gt;1&lt;/a&gt; &lt;br&gt;
has ended. The voting results are: 25 Yes, 0 No, 0 Abstain.&lt;/p&gt;
&lt;p&gt;According to the results, the RFC is now officially accepted.&lt;/p&gt;
&lt;p&gt;Thanks, &lt;br&gt;
Weilin Du&lt;/p&gt;
</description><guid>tencent_2EE694C67AA3C98A5E82D361893311F8B80A@qq.com</guid><pubDate>Thu, 22 Oct 2026 01:44:18 +0000</pubDate></item><item><title>[RFC] Io\Terminal</title><link>https://externals.io/message/132896</link><description>&lt;p&gt;Hi Tim,&lt;/p&gt;
&lt;p&gt;I suggest to wait with the vote for things to have calmed down.&lt;/p&gt;
&lt;p&gt;Understood, sorry about the timing. I’ll hold off on the October 23 vote &lt;br&gt;
and give everyone more time to review. I’ll send a fresh Intent to Vote &lt;br&gt;
notice once things have settled down.&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Pratik&lt;/p&gt;
</description><guid>CA+9BsNeZkCrhP89r_CLK7t8Qn4ALTFwcNxu9EWa5nZpB9scS8w@mail.gmail.com</guid><pubDate>Wed, 21 Oct 2026 18:44:53 +0000</pubDate></item><item><title>[RFC] Io\Terminal</title><link>https://externals.io/message/132895</link><description>&lt;p&gt;Hi&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I plan to open voting on the Io\Terminal RFC on Friday, October 23.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.php.net/rfc/io_terminal" rel="nofollow" target="_blank"&gt;https://wiki.php.net/rfc/io_terminal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If there are any further questions or concerns, please let me know.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Large parts of the core team have been busy in the past week(s) due to &lt;br&gt;
today's security release. I assume not everyone has been able to catch &lt;br&gt;
up with RFCs in that time (me included, I did not get around to reading &lt;br&gt;
the latest iteration of your - non-trivial - RFC).&lt;/p&gt;
&lt;p&gt;I suggest to wait with the vote for things to have calmed down.&lt;/p&gt;
&lt;p&gt;Best regards &lt;br&gt;
Tim Düsterhus&lt;/p&gt;
</description><guid>eca9827d-2234-4d07-8fb7-7825adc6e8f7@bastelstu.be</guid><pubDate>Wed, 21 Oct 2026 18:21:15 +0000</pubDate></item><item><title>PHP 8.6.0RC4 is available for testing</title><link>https://externals.io/message/132894</link><description>&lt;p&gt;PHP 8.6.0RC4 has just been released and may be downloaded from &lt;br&gt;
&lt;a href="https://downloads.php.net/~mbeccati/" rel="nofollow" target="_blank"&gt;https://downloads.php.net/~mbeccati/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or use the git tag: php-8.6.0RC4&lt;/p&gt;
&lt;p&gt;This version also contains the fixes for two critical vulnerabilities &lt;br&gt;
that can allow unauthenticated remote code execution. Everyone running &lt;br&gt;
earlier builds of PHP 8.6.0 is strongly encouraged to update immediately.&lt;/p&gt;
&lt;p&gt;This is an early test release and not intended for production use.&lt;/p&gt;
&lt;p&gt;Windows binaries are available at: &lt;br&gt;
&lt;a href="https://www.php.net/pre-release-builds.php#windows" rel="nofollow" target="_blank"&gt;https://www.php.net/pre-release-builds.php#windows&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please test it carefully, and report any bugs at &lt;br&gt;
&lt;a href="https://github.com/php/php-src/issues/new?template=bug_report.yml" rel="nofollow" target="_blank"&gt;https://github.com/php/php-src/issues/new?template=bug_report.yml&lt;/a&gt; &lt;br&gt;
on GitHub.&lt;/p&gt;
&lt;p&gt;8.6.0RC5 should be expected in ~2 weeks, i.e. on 5 Nov 2026.&lt;/p&gt;
&lt;p&gt;Hash values and PGP signatures can be found below or at &lt;br&gt;
&lt;a href="https://gist.github.com/mbeccati/39f97a084c818707537c9316206eb74f" rel="nofollow" target="_blank"&gt;https://gist.github.com/mbeccati/39f97a084c818707537c9316206eb74f&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you, and happy testing!&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Matteo Beccati, Joe Ferguson &amp;amp; Daniel Scherzer&lt;/p&gt;
&lt;p&gt;php-8.6.0RC4.tar.bz2 &lt;br&gt;
SHA256 hash: &lt;br&gt;
60d433d768e9c017632a0402048b0d189979d7659483db65df6790018e10d306 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iHUEABYKAB0WIQQBaJXemkdREdU3puaRNP8wvFqZtQUCatjPwAAKCRCRNP8wvFqZ &lt;br&gt;
tYpbAQCNKU7pP3CYk7m/V7HqJPE38BAuxRPSBsCHh6yKEGBRnwEA9UzLO1WLNcTB &lt;br&gt;
VjMJrBMTkvCzhK0VxrwbffAKh7qL6wU= &lt;br&gt;
=UU3o &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.6.0RC4.tar.gz &lt;br&gt;
SHA256 hash: &lt;br&gt;
ac4e19a92fc2d8a6a3b5310b149330475e602a8fd8f9278976bb1ee1b6b6665e &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iHUEABYKAB0WIQQBaJXemkdREdU3puaRNP8wvFqZtQUCatjPwAAKCRCRNP8wvFqZ &lt;br&gt;
tcJLAPwPRYRuJ1oJoRvBxBp3MMWokuV6y6jeYeHoC2EVIKozVQEAi3FOu/zGM6YA &lt;br&gt;
vQRUHxI7WyYBxfdSoDJVN846Zu3lkAk= &lt;br&gt;
=Rz8p &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.6.0RC4.tar.xz &lt;br&gt;
SHA256 hash: &lt;br&gt;
93f208da9ae059bf6863b0e1d101e6c6475a7b0f0acbf6c084950ab522f514d8 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iHUEABYKAB0WIQQBaJXemkdREdU3puaRNP8wvFqZtQUCatjPwAAKCRCRNP8wvFqZ &lt;br&gt;
tSmpAQDoZzynreTcJG4x8ORk/37jLFkpYanVUs5AfQoUriSFlwEA2AnSbnXiDtae &lt;br&gt;
mZtN087ADtwF9DjmDNz1stVLbjHA0QE= &lt;br&gt;
=ubPo &lt;br&gt;
-----END PGP SIGNATURE&lt;/p&gt;
</description><guid>407b1a5d-629a-40ac-9b26-865734660f3d@php.net</guid><pubDate>Wed, 21 Oct 2026 16:21:03 +0000</pubDate></item><item><title>PHP 8.4.27 Released</title><link>https://externals.io/message/132893</link><description>&lt;p&gt;The PHP development team announces the immediate availability of PHP 8.4.27.&lt;/p&gt;
&lt;p&gt;This is a security release fixing two critical vulnerabilities (CVE-2026-109618, CVE-2026-109619) &lt;br&gt;
that can allow unauthenticated remote code execution.&lt;/p&gt;
&lt;p&gt;All PHP 8.4 users are advised to upgrade to this version.&lt;/p&gt;
&lt;p&gt;There are no complete mitigations, updating is the only safe choice.&lt;/p&gt;
&lt;p&gt;See the security advisory for details: &lt;br&gt;
&lt;a href="https://www.php.net/archive/2026.php#2026-10-21-5" rel="nofollow" target="_blank"&gt;https://www.php.net/archive/2026.php#2026-10-21-5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For source downloads of PHP 8.4.27 please visit our downloads page. &lt;br&gt;
Windows binaries can be found on the PHP for Windows site. &lt;br&gt;
The list of changes is recorded in the ChangeLog.&lt;/p&gt;
&lt;p&gt;Release Announcement: &lt;a href="https://php.net/releases/8_4_27.php"&gt;https://php.net/releases/8_4_27.php&lt;/a&gt; &lt;br&gt;
Downloads:            &lt;a href="https://php.net/downloads"&gt;https://php.net/downloads&lt;/a&gt; &lt;br&gt;
Windows downloads:    &lt;a href="https://www.php.net/downloads.php?os=windows&amp;amp;version=8.4"&gt;https://www.php.net/downloads.php?os=windows&amp;amp;version=8.4&lt;/a&gt; &lt;br&gt;
Changelog:            &lt;a href="https://php.net/ChangeLog-8.php#8.4.27"&gt;https://php.net/ChangeLog-8.php#8.4.27&lt;/a&gt; &lt;br&gt;
Release Manifest:     &lt;a href="https://gist.github.com/NattyNarwhal/fba184b51d4397c46a082e71f10ee295"&gt;https://gist.github.com/NattyNarwhal/fba184b51d4397c46a082e71f10ee295&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Many thanks to all the contributors and supporters!&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Calvin Buckley, Saki Takamachi, and Eric Mann&lt;/p&gt;
&lt;p&gt;php-8.4.27.tar.bz2 &lt;br&gt;
SHA256 hash: b2530a877c722f4b08c9e174a30cb08bac2b7e1903ee6e9e315f0aa9f5f82c24 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iJEEABYKADkWIQSdf5mgy48FyKaVjWJWqXr3YAo5pgUCatYuXRsUgAAAAAAEAA5t &lt;br&gt;
YW51MiwyLjUrMS4xMiwwLDMACgkQVql692AKOaZJ+QD+N5jC7Og89QDafkw23xHB &lt;br&gt;
7YML1Ad26UiFzG1wcMENZRIA/066M0vjg+Q1x2HQi4f+07YtqhCIN4IZqiDQEzUz &lt;br&gt;
xAcE &lt;br&gt;
=MAOU &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.4.27.tar.gz &lt;br&gt;
SHA256 hash: 5bafed9994c1a49796b25b5f61c22c9183bfe046b6acc7b363842d03c77f972f &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iJEEABYKADkWIQSdf5mgy48FyKaVjWJWqXr3YAo5pgUCatYuXRsUgAAAAAAEAA5t &lt;br&gt;
YW51MiwyLjUrMS4xMiwwLDMACgkQVql692AKOaY3qAEAgkdyhOWhQhtETdt3JYNZ &lt;br&gt;
ikZrPY9u29jZaMmjoPj8ubEA/24terMZUo3PRBzmb7phybo6A0IK7Fu3GzqZNKsR &lt;br&gt;
ub0H &lt;br&gt;
=lyID &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.4.27.tar.xz &lt;br&gt;
SHA256 hash: dcf93923b0e38e0d5252b25b796520b5a47761a08b3488b6d0b5d1115764d3f0 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iJEEABYKADkWIQSdf5mgy48FyKaVjWJWqXr3YAo5pgUCatYuXRsUgAAAAAAEAA5t &lt;br&gt;
YW51MiwyLjUrMS4xMiwwLDMACgkQVql692AKOaZf7gEA7j/NMWQy9TbvQ4IhAajS &lt;br&gt;
gOO1tgMmpSTh3sPTOQQWfIkA/R363Ndrs3VJxYGx1pSZcstwfCwYXWbhUNGUsu6Z &lt;br&gt;
PjEJ &lt;br&gt;
=uvS8 &lt;br&gt;
-----END PGP SIGNATURE&lt;/p&gt;
</description><guid>73C3A6A5-CC5C-4C20-86E2-62BF077D8E8F@cmpct.info</guid><pubDate>Wed, 21 Oct 2026 14:32:43 +0000</pubDate></item><item><title>PHP 8.2.35 Released!</title><link>https://externals.io/message/132892</link><description>&lt;blockquote&gt;
&lt;p&gt;The PHP development team announces the immediate availability of PHP &lt;br&gt;
8.2.35.&lt;/p&gt;
&lt;p&gt;This is a security release fixing two critical vulnerabilities &lt;br&gt;
(CVE-2026-109618, CVE-2026-109619) &lt;br&gt;
that can allow unauthenticated remote code execution.&lt;/p&gt;
&lt;p&gt;All PHP 8.2 users are advised to upgrade to this version.&lt;/p&gt;
&lt;p&gt;There are no complete mitigations, updating is the only safe choice.&lt;/p&gt;
&lt;p&gt;See the security advisory for details: &lt;br&gt;
&lt;a href="https://www.php.net/archive/2026.php#2026-10-21-5" rel="nofollow" target="_blank"&gt;https://www.php.net/archive/2026.php#2026-10-21-5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For source downloads of PHP 8.2.35 please visit our downloads page. &lt;br&gt;
Windows binaries can be found on the PHP for Windows site. &lt;br&gt;
The list of changes is recorded in the ChangeLog.&lt;/p&gt;
&lt;p&gt;Release Announcement: &lt;a href="https://php.net/releases/8_2_35.php"&gt;https://php.net/releases/8_2_35.php&lt;/a&gt; &lt;br&gt;
Downloads:            &lt;a href="https://php.net/downloads"&gt;https://php.net/downloads&lt;/a&gt; &lt;br&gt;
Windows downloads:    &amp;lt; &lt;br&gt;
&lt;a href="https://www.php.net/downloads.php?os=windows&amp;amp;version=8.2&amp;gt" rel="nofollow" target="_blank"&gt;https://www.php.net/downloads.php?os=windows&amp;amp;version=8.2&amp;gt&lt;/a&gt;; &lt;br&gt;
Changelog:            &lt;a href="https://php.net/ChangeLog-8.php#8.2.35"&gt;https://php.net/ChangeLog-8.php#8.2.35&lt;/a&gt; &lt;br&gt;
Release Manifest:     &amp;lt; &lt;br&gt;
&lt;a href="https://gist.github.com/saundefined/35fb84fc90161b9e920a0992bda7a47c&amp;gt" rel="nofollow" target="_blank"&gt;https://gist.github.com/saundefined/35fb84fc90161b9e920a0992bda7a47c&amp;gt&lt;/a&gt;;&lt;/p&gt;
&lt;p&gt;Many thanks to all the contributors and supporters!&lt;/p&gt;
&lt;p&gt;Pierrick Charron, Sergey Panteleev &amp;amp; Ben Ramsey&lt;/p&gt;
&lt;p&gt;php-8.2.35.tar.bz2 &lt;br&gt;
SHA256 hash: &lt;br&gt;
0f43efd1ac24d4f90002c8d4d570bf4c4d59fa14313bf270aae8cf04d9dfdef3 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQJPBAABCAA5FiEE5gkT5N8gmQfY4w2WZZqXyc8qeVoFAmrVx/4bFIAAAAAABAAO &lt;br&gt;
bWFudTIsMi41KzEuMTIsMCwzAAoJEGWal8nPKnlaFq0P/2W91rkguw9eQggyFMTs &lt;br&gt;
l5pGJGNZrashKQ6LfOyesKPFAXLDxOKBf4LJBaSDt4sNFXoaCK+cMgZfaH4xOakS &lt;br&gt;
79aQPJx1oxdAEjVtwZ+0QY/dLo3dE/0AteohYuj517k1xQVA1NhLrWltuCW0JIZP &lt;br&gt;
b+P8mn7d//MtwRX936tRVdO4IxljUe5Ns/QjVeIbH+4UpCuWJ+kmgFFQZMTj5NaR &lt;br&gt;
oIjFRqyKT/CD5KtlTIfeXaXnKjqEvt8RFxZQRRqikhY3Ef1ZcMmKc4R6Rp2Kp9g9 &lt;br&gt;
p7uaiIid0sPXggMiARqZ0QUbfhhZJbquZlPgc9i/RMsIUPSz6u+3QAzIoKbg1z9z &lt;br&gt;
3syVMg00mn1H/7QJQRMzVlBTXKa7Ne0VOToQXPxCiGIwf8ccG8vFb8GpKLVcaS/n &lt;br&gt;
SPV9pjrCzLjaguM5UtH1iwQi/H5HxRhEfQI+P/Yq/dJKnhDVJJc6nmPi5qa4ePLZ &lt;br&gt;
/azbGp1jvUDxAyBLq9vXiN5Derv20YTf/4qdXVGUmtVumg3CIpUT3s0jI+JA7lnF &lt;br&gt;
r3hoVyhVOMi3+jEVy47u8TrCU5pR4GTLz1+Cyhq8spagdY3yMzDLBmJ/0F1eqP+Y &lt;br&gt;
nqeB5538cI69U1aqwALtzE2FMy44OocyovgvTwBnHg5bIU2farKJJ2O2glZpPTiA &lt;br&gt;
NUJcE5ydh9cTJx7JoEuUHKJ6 &lt;br&gt;
=T7Lq &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.2.35.tar.gz &lt;br&gt;
SHA256 hash: &lt;br&gt;
9db4204f0a2d1911277ae832185e07bb4c3b3559772753a70d2968ca346d6910 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQJPBAABCAA5FiEE5gkT5N8gmQfY4w2WZZqXyc8qeVoFAmrVyAcbFIAAAAAABAAO &lt;br&gt;
bWFudTIsMi41KzEuMTIsMCwzAAoJEGWal8nPKnlaCTkP/i+SgGgM6SwcL1gg9fXn &lt;br&gt;
fn31m/MEPGmbibQ0qirWURTAyLrU4Fdxn/JbZnU6dnC75MiZoB7l+Geux1vopJcq &lt;br&gt;
fPNiRptjsoGJ5UhgNqokiSL52CrVXdaf8IRiW/2uAeOaVjK+oM0cC9CBz21AkKzG &lt;br&gt;
EVNoWslWMHW4FI5HunSu7l1OoptGN2g5DIUeEoWxE8PI0VNlBmRtdwED4OOVvWr1 &lt;br&gt;
F1AyiLcsOZEXegWvW3A16O5gA9TlU+yWU+HGkikyPEGRlb0BT2f9ntUwyS1FkzAJ &lt;br&gt;
dEk2txvvcPdhVT/ZDGRpnk2MGDbSXf3nKxs/509x2MrDemT7R0A85Vxd2b3iRSR2 &lt;br&gt;
t/etfQxOwGk4l3265ydOMBDbXgUfKUiPkvGYhUDMgMnkfI1Cj/SfJDoGyaDtbOn5 &lt;br&gt;
xiIuKwFlRPPKgmJkU85j9A/+zQsZEfGvEGDCNt6mSnXHw5m+4nxbs563aE+4XqXh &lt;br&gt;
BtBeykSkoNsRj8ijKpJJC/Ygd0+faNscww/imbsAYNgIXBNgz+ApjxEa96mcVVU8 &lt;br&gt;
s++wlleO0+KTFsFWGgw/pXJwF8FO0SnWMDvLMHTXeN6wLxEef3f6EL+X052ixB9m &lt;br&gt;
r+kI7tk+dWWKDj07Uja/CHnmreHTJBZ51tHLO7lXbHRSkykFPpze7GmxmEzXUYZo &lt;br&gt;
KBzDVOaFSv3PrHeoLZDXqEvf &lt;br&gt;
=dsL2 &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.2.35.tar.xz &lt;br&gt;
SHA256 hash: &lt;br&gt;
5737b98601fe5ab1b8c5db0c82ed3158acb9283ed3081ffe2faffb9ac81455e6 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQJPBAABCAA5FiEE5gkT5N8gmQfY4w2WZZqXyc8qeVoFAmrVyAgbFIAAAAAABAAO &lt;br&gt;
bWFudTIsMi41KzEuMTIsMCwzAAoJEGWal8nPKnlakfEP/iFvT4mcDQcXBeMM6CRm &lt;br&gt;
SzjpTs7moCgkxQzVISdVOmbFlmdUGjXFgvjlnKbOpw9PNhaUDOR3FfhLYB1XKKCs &lt;br&gt;
k5XsvF8C9Qh0qM3whwfKXUA2fz7GFsFX8Oe7cOYxKrtdld0rxvm7EbVCpHv+DF34 &lt;br&gt;
TAjKRKL/p4aH5ntfHuuV0+Ow2J1D+Ko8vs3EBnxupPxmbn85W8BEVAj6hRiUFmd+ &lt;br&gt;
zU3pGdBv/naQG/N+NCiSWkWn7VghY6mUf1nwXkdzFrVfQBSvbG5fxiO41RTHzHKB &lt;br&gt;
iSzOtaMK8Wy6M2+mGdn+UlY+5nSqiZk/cWmTO3mXlRrr1YPTNKnEnrkcDKwCNguC &lt;br&gt;
7nTwNblOCaugiOlNNXrXbye9mlzsqFkq9ZrSqb52h5ctDPeXMDpZ8iJKNtDqfX77 &lt;br&gt;
uoUbbRoDzA4xz6osMj237Mtbu6kqPI+QOdAOfBfRiCYWt8SVbsXD+qGUU8AffqWR &lt;br&gt;
R+fmMlm92ngkhITQx6jN3csTflgWCsBSrR5xirpy5fehMDGZpZ1BSFgILlK3PUPw &lt;br&gt;
Bpi+rCTiTBKni42uWrqNMXxVYGVS/MIWDK5alXQ6kE5ThwuNMSMaMJvJxZuTViUi &lt;br&gt;
r9o8X6IonYC0Et3ZpJuWKVjRcwSYzOZ/tKGRB00LKAKXyFyylWhVffAYzEgZSwvH &lt;br&gt;
qEQfrM2/LyS0lMeOkhjSStPB &lt;br&gt;
=P6Hg &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My thanks to everyone who worked hard to fix these CVEs the past few days!&lt;/p&gt;
</description><guid>CANS-=pc4DMPYxEe-yXX3akMFFszcmn60Qb-=nkvVm0H1UcAP=w@mail.gmail.com</guid><pubDate>Wed, 21 Oct 2026 14:16:54 +0000</pubDate></item><item><title>PHP 8.5.12 Released</title><link>https://externals.io/message/132891</link><description>&lt;p&gt;The PHP development team announces the immediate availability of PHP 8.5.12. &lt;br&gt;
This is a security release.&lt;/p&gt;
&lt;p&gt;This is a security release fixing two critical vulnerabilities &lt;br&gt;
(CVE-2026-109618, &lt;br&gt;
CVE-2026-109619) that can allow unauthenticated remote code execution.&lt;/p&gt;
&lt;p&gt;All PHP 8.5 users are encouraged to upgrade to this version.&lt;/p&gt;
&lt;p&gt;There are no complete mitigations, updating is the only safe choice.&lt;/p&gt;
&lt;p&gt;See the security advisory for details: &lt;br&gt;
&lt;a href="https://www.php.net/archive/2026.php#2026-10-21-5" rel="nofollow" target="_blank"&gt;https://www.php.net/archive/2026.php#2026-10-21-5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For source downloads of PHP 8.5.12 please visit our downloads page. &lt;br&gt;
Windows binaries can be found on the same page. &lt;br&gt;
The list of changes is recorded in the ChangeLog.&lt;/p&gt;
&lt;p&gt;Release Announcement: &lt;a href="https://php.net/releases/8_5_12.php"&gt;https://php.net/releases/8_5_12.php&lt;/a&gt; &lt;br&gt;
Downloads:            &lt;a href="https://php.net/downloads"&gt;https://php.net/downloads&lt;/a&gt; &lt;br&gt;
Windows downloads:    &amp;lt; &lt;br&gt;
&lt;a href="https://www.php.net/downloads.php?os=windows&amp;amp;version=8.5&amp;gt" rel="nofollow" target="_blank"&gt;https://www.php.net/downloads.php?os=windows&amp;amp;version=8.5&amp;gt&lt;/a&gt;; &lt;br&gt;
Changelog:            &lt;a href="https://php.net/ChangeLog-8.php#8.5.12"&gt;https://php.net/ChangeLog-8.php#8.5.12&lt;/a&gt; &lt;br&gt;
Release Manifest:     &amp;lt; &lt;br&gt;
&lt;a href="https://gist.github.com/DanielEScherzer/9fce78e81e004f0398e249e1fe0df5b8&amp;gt" rel="nofollow" target="_blank"&gt;https://gist.github.com/DanielEScherzer/9fce78e81e004f0398e249e1fe0df5b8&amp;gt&lt;/a&gt;;&lt;/p&gt;
&lt;p&gt;Many thanks to all the contributors and supporters!&lt;/p&gt;
&lt;p&gt;Regards, &lt;br&gt;
Daniel Scherzer, Volker Dusch, and Pierrick Charron&lt;/p&gt;
&lt;p&gt;php-8.5.12.tar.bz2 &lt;br&gt;
SHA256 hash: &lt;br&gt;
ffb60edc437ced63b5137e4984db379a8111c50049c711510d8b958277efc1a8 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQIzBAABCAAdFiEE2VwDvHAr6VFTRK4zdORLyQZ3AaUFAmrWUKQACgkQdORLyQZ3 &lt;br&gt;
AaU1QRAAj951A3VHXxL+rfVce64T0cCI6bde+BqSWmxMifKN29UkVDOrzxkzNYZK &lt;br&gt;
993NLsmMPMN00FlJsXXlZ8RuOBgTzv8HHnKTjJdxtbXDlaHWiYNZT5hIY9/JpLe8 &lt;br&gt;
1pHztBB4GwGxtYqFleg2w0ya52To191dTxqkbE9xMyNGxY6b14K1f+CyWkYlbxjD &lt;br&gt;
c/mnsCJ26zzVWfU1ZhEIGjC5ykXQcIZRwMbwdywnvQo63DzxqT5gFwKq2Lkdy0oM &lt;br&gt;
/RCXWYBQdXsLbkanC2jzAceubm1Rk1MQHMtbvEkY/IwkGR73ky4q/Yig99K3grID &lt;br&gt;
sVYXUVhqxMnPFWMManQPC+aKE9rrtgJkY84rDLFYWTmi7qW81lYBOLWizH5oFhBY &lt;br&gt;
fSomfaNNqGuddn9Swrqn07R+gA1JAdiSWq1ViIrE5TN2J6ytey0n4mepThdNq4oZ &lt;br&gt;
FN+jmH/MkftDWMgDrt0iSq/Kk4nAcjsBc28YIku29J45J9zE9HkejoEBaTzDXUdC &lt;br&gt;
Y5IIjlF8NEzPZJhppM4WmvP1HzcocmtMjzjyBY82Z+sw+oUzh+6thCU4MYIV89YF &lt;br&gt;
gQvVhM77r/3MxsA3JNPgF9B6e/vK9JEptlAl9gzLDwJCW+VCWg4wWgTFvW4Eah32 &lt;br&gt;
kMwu8qYX/8hrPv4JKvqeADfGWUJvLKGQV9REeA6jBSy9yD+ZvC4= &lt;br&gt;
=gNxr &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.5.12.tar.gz &lt;br&gt;
SHA256 hash: &lt;br&gt;
81a0f450349e84b08eb43faa85f8a4c835684f3cc1c50471775d1317a046c525 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQIzBAABCAAdFiEE2VwDvHAr6VFTRK4zdORLyQZ3AaUFAmrWUKgACgkQdORLyQZ3 &lt;br&gt;
AaVyQg//SiL5miUAcCERQkmIpKyk9ZNvTX1NYhs5YEF+eNpUoUAEHUBdmbAqJ17G &lt;br&gt;
P6Z8cMurmQqGVX2dc4YSuHqjmFiBzEQpAOqzVg9AJaKFm4L9mQyI3uB/+p+T5Eu7 &lt;br&gt;
2biVKD1U4EcJ0AWwsCLB1wOH3zY4FS+flovZLiM8o+VEnJnoM+X8THbF6NuWyjQk &lt;br&gt;
5v8/5xrPFHMycae63gbq+e9P7OKuaMdOXmkdTGzl20sn14M2rmQoqnExBkMb81fV &lt;br&gt;
lC7AT9X4X7ATOCkzBNAuY4MGSqJmnPQrh8SSSuEmNqltqCIw56u1lvf7x1QXPQiJ &lt;br&gt;
GPHkzfiFf9+03QO95jos1RDPnNNaKJsGc/GR/5KHKzSEbA9nDTPfTBIffQOAiNu5 &lt;br&gt;
Ii3Otv4Q0cU7d7lHf0oJ9U/gdU/Ixv6Y8gYs2gEABu4T1v1kumObMSaT4wxSNeJh &lt;br&gt;
UQqOX//JCz+x9cAaZSie1qTUObmKDbP4HnOwauY6fVfdYXcVTLB5KekhCrbEULT8 &lt;br&gt;
/A2NhOZiQHAigwE6EfI1L9Qwta5/YFLkI9xbY9fLi31HnCUNc70X36FzokVTYQeb &lt;br&gt;
ju9d9VgpFhe57MTjOXiJExAcWbSFsM7smDYibWQak4pGT/kXCQ8iJT686aovHso+ &lt;br&gt;
rbhTDnde55bxv7ieZcnr42AjwlCIQ2lFexmWUan1CHyE2sczjvg= &lt;br&gt;
=bZwM &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.5.12.tar.xz &lt;br&gt;
SHA256 hash: &lt;br&gt;
08bc2eba2a588654ade1357174aa646b761556c862dda0678345ee29ed481209 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQIzBAABCAAdFiEE2VwDvHAr6VFTRK4zdORLyQZ3AaUFAmrWUKgACgkQdORLyQZ3 &lt;br&gt;
AaWt8BAAkiRCqB8qc8OoXos8YBES/67MKcpKh5es0geSOG8TuuxkkNG7rZfpAAU7 &lt;br&gt;
G32U30SCFYCpUZT5C6OQWV0EHdqDxvgRdpv5v3C/nxQSw320DyYIbJPWByxtq1WE &lt;br&gt;
V/KO4/PtGLPNIC1Tqgh3stxh1sOYtAPY+A07xd59l8rYpw0/hRWcpufrmrmx46te &lt;br&gt;
TrH3ZNEXkBZPWmaS2gcUkB3hDgol5gB+0vtAedOef3uQcWnmxTOawrIaAoTNtGIU &lt;br&gt;
3tQQHtrzcPSimV9LBlScL1T8KZFJKb4ZMvYOF7WJbmbPgWbbnqqb/wznJb7/KNRh &lt;br&gt;
HmAuhDe2cPuJuN2J11NAZ1bw+/6AvTok8Vt0jyEPRaTVcUW7NG0PZgLsYf2hPXbG &lt;br&gt;
YETMwl39IDM7CN+YPUpYOgdXDlrjwu3ZB7A563y7L23kGidlO6oPU4u+Lp2zCZ1S &lt;br&gt;
vPWxDuR3KkWKTjwAJiwfAJEAmPvXl2lSrMkqldP9soiGSH7BFHPcBnB12lJTtTXy &lt;br&gt;
VcJwe9plmG8K3LFYYnLAZjVGfl+xqH2RRRxkmt8sUaKNQSxquXnTOfF4CpZSs4E4 &lt;br&gt;
dV/juvxwUla4ahqR29UvlhmuR/fI4wgoifmCIJQxMmakBCnBGxcRaZReBwugDZRh &lt;br&gt;
7v5UfTk06YqT4kFcAsqz40EeJqvRyLT8LqkaaEOBlP8T1VSxuZU= &lt;br&gt;
=EFmu &lt;br&gt;
-----END PGP SIGNATURE&lt;/p&gt;
</description><guid>CALaXqqTFRXvJSMFd8oVTQYSqcSk9zk4LdosH0TfxPe1LyeweeQ@mail.gmail.com</guid><pubDate>Wed, 21 Oct 2026 14:03:59 +0000</pubDate></item><item><title>PHP 8.3.36 Released</title><link>https://externals.io/message/132890</link><description>&lt;p&gt;The PHP development team announces the immediate availability of PHP 8.3.36.&lt;/p&gt;
&lt;p&gt;This is a security release fixing two critical vulnerabilities &lt;br&gt;
(CVE-2026-109618, CVE-2026-109619) that can allow unauthenticated remote &lt;br&gt;
code execution.&lt;/p&gt;
&lt;p&gt;All PHP 8.3 users are encouraged to upgrade to this version.&lt;/p&gt;
&lt;p&gt;There are no complete mitigations, updating is the only safe choice.&lt;/p&gt;
&lt;p&gt;See the security advisory for details: &lt;br&gt;
&lt;a href="https://www.php.net/archive/2026.php#2026-10-21-5" rel="nofollow" target="_blank"&gt;https://www.php.net/archive/2026.php#2026-10-21-5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For source downloads of PHP 8.3.36 please visit our downloads page. &lt;br&gt;
Windows binaries can be found on the PHP for Windows site. &lt;br&gt;
The list of changes is recorded in the ChangeLog.&lt;/p&gt;
&lt;p&gt;Release Announcement: &lt;a href="https://php.net/releases/8_3_36.php"&gt;https://php.net/releases/8_3_36.php&lt;/a&gt; &lt;br&gt;
Downloads:            &lt;a href="https://php.net/downloads"&gt;https://php.net/downloads&lt;/a&gt; &lt;br&gt;
Windows downloads: &lt;br&gt;
&lt;a href="https://www.php.net/downloads.php?os=windows&amp;amp;version=8.3"&gt;https://www.php.net/downloads.php?os=windows&amp;amp;version=8.3&lt;/a&gt; &lt;br&gt;
Changelog: &lt;a href="https://php.net/ChangeLog-8.php#8.3.36"&gt;https://php.net/ChangeLog-8.php#8.3.36&lt;/a&gt; &lt;br&gt;
Release Manifest: &lt;br&gt;
 &lt;a href="https://gist.github.com/ericmann/bd87f4e5a8b6d0a0a9f7bda353cc4283"&gt;https://gist.github.com/ericmann/bd87f4e5a8b6d0a0a9f7bda353cc4283&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Many thanks to all the contributors and supporters!&lt;/p&gt;
&lt;p&gt;Eric Mann, Jakub Zelenka, and Pierrick Charron&lt;/p&gt;
&lt;p&gt;php-8.3.36.tar.bz2 &lt;br&gt;
SHA256 hash: &lt;br&gt;
46f4b45e3688ed2b1819015a7b532c15b51cc055bdd3b13fd00ddfeebeedcd5f &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQIzBAABCAAdFiEESx/A2d+SMhztn2FdvsVV4ioUNVMFAmrWI18ACgkQvsVV4ioU &lt;br&gt;
NVP08hAAkPHoBkbZZrd++fuyrS/8mz3qBrGBqxvfvWQIAK8M1T/5iRzSvzQuUWy1 &lt;br&gt;
6QYEnTedJLyFnM4f0mMrtDMswj7BkWz8SgJ8Akyh4GX+OVeg3Q8FNvhb09nqTrLg &lt;br&gt;
/Soy6z7AcKcnrofFpJhuLcoTBxp7UamJQQgA7zOICjjH2CDOxxEFcek/DklvCW1R &lt;br&gt;
9gIlMYCk3VXNmAqHU7STvPLnrBzX/xKkqFXnqaLjWMBzgL9n0r0lHyPq+2JDHMho &lt;br&gt;
UyFCcmz9/c3gwx8/OZvnA97+w/ZQf5FjnB4z2DWuVb+TJiAzKBpjniqullnrH5LA &lt;br&gt;
B8UPu5vrxUECkHNMni+Tou6Y9i2t0SF2jBYaTF/c9fXBRyp+ymiLciEQMgHAhRIZ &lt;br&gt;
gAcI3KbJe/z6tUGiOs2Wxoeot8FS5U0o5OwNE6iurDg+iC3PpwmOyorz3psNdlpd &lt;br&gt;
nRBVGL+b32KNg/co7nT/GU6LOMetDR5uWf2+f0C4tlmHnQXT9uyQZWljY9xkKUjK &lt;br&gt;
Uqph8grS/H3m2YiGH7hRTro8Qj8CfX/MZAky/l2fU3O8wPa/1WIkEBSBLYpjlrDB &lt;br&gt;
17gzXQxFBdjEhQx4E7kpyj03Va7hc9at9nAG4Kjc7W8e92uiOn2RgjluuNuWnp2m &lt;br&gt;
oqjdQSKzItn0b5pp+1BfwUTbkCpiz/JwpQZKuJPbse88p2/C/G0= &lt;br&gt;
=JPY/ &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.3.36.tar.gz &lt;br&gt;
SHA256 hash: &lt;br&gt;
c93f3441f87f6ab156bef4432db215d7e61ca2c0183bb3a2aa28d9886ab59f53 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQIzBAABCAAdFiEESx/A2d+SMhztn2FdvsVV4ioUNVMFAmrWI18ACgkQvsVV4ioU &lt;br&gt;
NVM5Uw/8CWc6ccvc2gwPb9Yq6fUlIZyeLZq1KZC3VE9dRphu0FEk+/hch7wMeBp5 &lt;br&gt;
GAHnYHcLyVEIfINywiArU4mkIhWtHPMowZKpzjx44hxzvsEmT+dcn99xcahIKER2 &lt;br&gt;
ehBbn0nw65Ki7fsi7yPqTLqqICXrdtDh6JiF2qIRFRXTq3bmQZ6gadM16ANK1gko &lt;br&gt;
IYFcvHsoj/+SeoXwver++PlseJp5H9gOA4qUV+OVgrVHMCEdnhyhtM+II+s9z6fB &lt;br&gt;
nv+va67QGz1S1Cxhv439vEnv/YFjAjWouZOzYO3SnoBzeWvvdod32zEQdiXz5N9v &lt;br&gt;
vKpkl45rJ+4hjpxaoHdmwfMzCVK8N7FV9l0YF24OqKdakcZgzI5LtYWphGmBRYjU &lt;br&gt;
e9yG7k1WyJVogb7nPay0UMXFjjyCMqMnXlK1BVuDwTh8xpPUf/s1FF0pqcUMbxog &lt;br&gt;
VX9ZU3HJNAlKi2JuHHF50lhngY5e4UK3Dp0+hX2clSWETo/hZHueYUj3zTz9ZnO9 &lt;br&gt;
XIYue3O4qfpLM6+P7LFXTB9Ht9wro4DxCLnAmIjUvRP8Uyq9r4PK6KtnSG3i4MrR &lt;br&gt;
S3WjkuIY8fo0pRHmm95ZReakgseAnZDjDRonjUp1kmv/xrT4X+l9m5C/wd2TfvTH &lt;br&gt;
wTI4x1l7fPNtaaQ6Qe3Z+GZQd95VafmbtnXA7/qNjrvlRwvc6OU= &lt;br&gt;
=LlH8 &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.3.36.tar.xz &lt;br&gt;
SHA256 hash: &lt;br&gt;
dd54693aa334c5c4d72e9aee96b082c2473750a18a6c1d105789c93a3b1692fd &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQIzBAABCAAdFiEESx/A2d+SMhztn2FdvsVV4ioUNVMFAmrWI18ACgkQvsVV4ioU &lt;br&gt;
NVNs+RAAj/QMSy3YSQwr+rkUD0qaMvO0fZET3dBNxEtdMCM1iQSWzBJi9Llty7De &lt;br&gt;
OfaCXOK/NZpO3CICJifir0XY9eU6uHWl7wpo8YQHXcQ5EirDX3jeNEHMoPnx3jsX &lt;br&gt;
NX7j4fpcj3hfLuZLW1vyKhVmXCenrhJDPS+buta5g79OXpGUrJ0hy2IFKmt049BO &lt;br&gt;
sxDOjQZANd46RApf8GapEvpDClkTTSnnEh8v0S9ripShe4oECTzW+bDKEtsZVImv &lt;br&gt;
xpZJqC0sJ7Y9i4M7dVqfNjohEfj+Mh0NvfR8l4PHHko5RVz7A3EueThM8WZ4i2qr &lt;br&gt;
iwKIOSBhdzcgfEGwKKGzO4yjcf3pCvcANh8Oa6En3fSXwoJgMZJhTczCh7cFJIQS &lt;br&gt;
e58b8dMmSAsQLcgB1LQr7hulHOQLt4lDzO/iR4rT3C3bBaZsZfjfyZxNMFxUFgSm &lt;br&gt;
ZUrXgGGbDqtAtoif80OzXLMT+S8G3dks/nRnn+hVy0QDxjawIGAIutZVAVSA9Ixp &lt;br&gt;
UsxS1N6v7/WWUHuuKBQEYib7N+QXPIgJrr5vF3D7s7bF3RN2jIDlIvKVvp/Bz2xr &lt;br&gt;
x7rKFtIN3XsLOkS9qlL4XcZN8gMZkLh04VJ7gmEO5L/mOkk+PJidMjbCimASERjJ &lt;br&gt;
/FjxHzlKkku17fn7E1T6LPmrIN1MvA0B66iJhXWgIoMp7h+bTqM= &lt;br&gt;
=FtbT &lt;br&gt;
-----END PGP SIGNATURE&lt;/p&gt;
</description><guid>db4f105f-5589-4a93-bac7-17531dd043dc@php.net</guid><pubDate>Wed, 21 Oct 2026 14:01:22 +0000</pubDate></item><item><title>PHP 8.2.35 Released!</title><link>https://externals.io/message/132889</link><description>&lt;p&gt;The PHP development team announces the immediate availability of PHP 8.2.35.&lt;/p&gt;
&lt;p&gt;This is a security release fixing two critical vulnerabilities (CVE-2026-109618, CVE-2026-109619) &lt;br&gt;
that can allow unauthenticated remote code execution.&lt;/p&gt;
&lt;p&gt;All PHP 8.2 users are advised to upgrade to this version.&lt;/p&gt;
&lt;p&gt;There are no complete mitigations, updating is the only safe choice.&lt;/p&gt;
&lt;p&gt;See the security advisory for details: &lt;br&gt;
&lt;a href="https://www.php.net/archive/2026.php#2026-10-21-5" rel="nofollow" target="_blank"&gt;https://www.php.net/archive/2026.php#2026-10-21-5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For source downloads of PHP 8.2.35 please visit our downloads page. &lt;br&gt;
Windows binaries can be found on the PHP for Windows site. &lt;br&gt;
The list of changes is recorded in the ChangeLog.&lt;/p&gt;
&lt;p&gt;Release Announcement: &lt;a href="https://php.net/releases/8_2_35.php"&gt;https://php.net/releases/8_2_35.php&lt;/a&gt; &lt;br&gt;
Downloads:            &lt;a href="https://php.net/downloads"&gt;https://php.net/downloads&lt;/a&gt; &lt;br&gt;
Windows downloads:    &lt;a href="https://www.php.net/downloads.php?os=windows&amp;amp;version=8.2"&gt;https://www.php.net/downloads.php?os=windows&amp;amp;version=8.2&lt;/a&gt; &lt;br&gt;
Changelog:            &lt;a href="https://php.net/ChangeLog-8.php#8.2.35"&gt;https://php.net/ChangeLog-8.php#8.2.35&lt;/a&gt; &lt;br&gt;
Release Manifest:     &lt;a href="https://gist.github.com/saundefined/35fb84fc90161b9e920a0992bda7a47c"&gt;https://gist.github.com/saundefined/35fb84fc90161b9e920a0992bda7a47c&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Many thanks to all the contributors and supporters!&lt;/p&gt;
&lt;p&gt;Pierrick Charron, Sergey Panteleev &amp;amp; Ben Ramsey&lt;/p&gt;
&lt;p&gt;php-8.2.35.tar.bz2 &lt;br&gt;
SHA256 hash: 0f43efd1ac24d4f90002c8d4d570bf4c4d59fa14313bf270aae8cf04d9dfdef3 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQJPBAABCAA5FiEE5gkT5N8gmQfY4w2WZZqXyc8qeVoFAmrVx/4bFIAAAAAABAAO &lt;br&gt;
bWFudTIsMi41KzEuMTIsMCwzAAoJEGWal8nPKnlaFq0P/2W91rkguw9eQggyFMTs &lt;br&gt;
l5pGJGNZrashKQ6LfOyesKPFAXLDxOKBf4LJBaSDt4sNFXoaCK+cMgZfaH4xOakS &lt;br&gt;
79aQPJx1oxdAEjVtwZ+0QY/dLo3dE/0AteohYuj517k1xQVA1NhLrWltuCW0JIZP &lt;br&gt;
b+P8mn7d//MtwRX936tRVdO4IxljUe5Ns/QjVeIbH+4UpCuWJ+kmgFFQZMTj5NaR &lt;br&gt;
oIjFRqyKT/CD5KtlTIfeXaXnKjqEvt8RFxZQRRqikhY3Ef1ZcMmKc4R6Rp2Kp9g9 &lt;br&gt;
p7uaiIid0sPXggMiARqZ0QUbfhhZJbquZlPgc9i/RMsIUPSz6u+3QAzIoKbg1z9z &lt;br&gt;
3syVMg00mn1H/7QJQRMzVlBTXKa7Ne0VOToQXPxCiGIwf8ccG8vFb8GpKLVcaS/n &lt;br&gt;
SPV9pjrCzLjaguM5UtH1iwQi/H5HxRhEfQI+P/Yq/dJKnhDVJJc6nmPi5qa4ePLZ &lt;br&gt;
/azbGp1jvUDxAyBLq9vXiN5Derv20YTf/4qdXVGUmtVumg3CIpUT3s0jI+JA7lnF &lt;br&gt;
r3hoVyhVOMi3+jEVy47u8TrCU5pR4GTLz1+Cyhq8spagdY3yMzDLBmJ/0F1eqP+Y &lt;br&gt;
nqeB5538cI69U1aqwALtzE2FMy44OocyovgvTwBnHg5bIU2farKJJ2O2glZpPTiA &lt;br&gt;
NUJcE5ydh9cTJx7JoEuUHKJ6 &lt;br&gt;
=T7Lq &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.2.35.tar.gz &lt;br&gt;
SHA256 hash: 9db4204f0a2d1911277ae832185e07bb4c3b3559772753a70d2968ca346d6910 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQJPBAABCAA5FiEE5gkT5N8gmQfY4w2WZZqXyc8qeVoFAmrVyAcbFIAAAAAABAAO &lt;br&gt;
bWFudTIsMi41KzEuMTIsMCwzAAoJEGWal8nPKnlaCTkP/i+SgGgM6SwcL1gg9fXn &lt;br&gt;
fn31m/MEPGmbibQ0qirWURTAyLrU4Fdxn/JbZnU6dnC75MiZoB7l+Geux1vopJcq &lt;br&gt;
fPNiRptjsoGJ5UhgNqokiSL52CrVXdaf8IRiW/2uAeOaVjK+oM0cC9CBz21AkKzG &lt;br&gt;
EVNoWslWMHW4FI5HunSu7l1OoptGN2g5DIUeEoWxE8PI0VNlBmRtdwED4OOVvWr1 &lt;br&gt;
F1AyiLcsOZEXegWvW3A16O5gA9TlU+yWU+HGkikyPEGRlb0BT2f9ntUwyS1FkzAJ &lt;br&gt;
dEk2txvvcPdhVT/ZDGRpnk2MGDbSXf3nKxs/509x2MrDemT7R0A85Vxd2b3iRSR2 &lt;br&gt;
t/etfQxOwGk4l3265ydOMBDbXgUfKUiPkvGYhUDMgMnkfI1Cj/SfJDoGyaDtbOn5 &lt;br&gt;
xiIuKwFlRPPKgmJkU85j9A/+zQsZEfGvEGDCNt6mSnXHw5m+4nxbs563aE+4XqXh &lt;br&gt;
BtBeykSkoNsRj8ijKpJJC/Ygd0+faNscww/imbsAYNgIXBNgz+ApjxEa96mcVVU8 &lt;br&gt;
s++wlleO0+KTFsFWGgw/pXJwF8FO0SnWMDvLMHTXeN6wLxEef3f6EL+X052ixB9m &lt;br&gt;
r+kI7tk+dWWKDj07Uja/CHnmreHTJBZ51tHLO7lXbHRSkykFPpze7GmxmEzXUYZo &lt;br&gt;
KBzDVOaFSv3PrHeoLZDXqEvf &lt;br&gt;
=dsL2 &lt;br&gt;
-----END PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;php-8.2.35.tar.xz &lt;br&gt;
SHA256 hash: 5737b98601fe5ab1b8c5db0c82ed3158acb9283ed3081ffe2faffb9ac81455e6 &lt;br&gt;
PGP signature: &lt;br&gt;
-----BEGIN PGP SIGNATURE-----&lt;/p&gt;
&lt;p&gt;iQJPBAABCAA5FiEE5gkT5N8gmQfY4w2WZZqXyc8qeVoFAmrVyAgbFIAAAAAABAAO &lt;br&gt;
bWFudTIsMi41KzEuMTIsMCwzAAoJEGWal8nPKnlakfEP/iFvT4mcDQcXBeMM6CRm &lt;br&gt;
SzjpTs7moCgkxQzVISdVOmbFlmdUGjXFgvjlnKbOpw9PNhaUDOR3FfhLYB1XKKCs &lt;br&gt;
k5XsvF8C9Qh0qM3whwfKXUA2fz7GFsFX8Oe7cOYxKrtdld0rxvm7EbVCpHv+DF34 &lt;br&gt;
TAjKRKL/p4aH5ntfHuuV0+Ow2J1D+Ko8vs3EBnxupPxmbn85W8BEVAj6hRiUFmd+ &lt;br&gt;
zU3pGdBv/naQG/N+NCiSWkWn7VghY6mUf1nwXkdzFrVfQBSvbG5fxiO41RTHzHKB &lt;br&gt;
iSzOtaMK8Wy6M2+mGdn+UlY+5nSqiZk/cWmTO3mXlRrr1YPTNKnEnrkcDKwCNguC &lt;br&gt;
7nTwNblOCaugiOlNNXrXbye9mlzsqFkq9ZrSqb52h5ctDPeXMDpZ8iJKNtDqfX77 &lt;br&gt;
uoUbbRoDzA4xz6osMj237Mtbu6kqPI+QOdAOfBfRiCYWt8SVbsXD+qGUU8AffqWR &lt;br&gt;
R+fmMlm92ngkhITQx6jN3csTflgWCsBSrR5xirpy5fehMDGZpZ1BSFgILlK3PUPw &lt;br&gt;
Bpi+rCTiTBKni42uWrqNMXxVYGVS/MIWDK5alXQ6kE5ThwuNMSMaMJvJxZuTViUi &lt;br&gt;
r9o8X6IonYC0Et3ZpJuWKVjRcwSYzOZ/tKGRB00LKAKXyFyylWhVffAYzEgZSwvH &lt;br&gt;
qEQfrM2/LyS0lMeOkhjSStPB &lt;br&gt;
=P6Hg &lt;br&gt;
-----END PGP SIGNATURE&lt;/p&gt;
</description><guid>C82EE943-225E-4466-BC56-512F4641729F@php.net</guid><pubDate>Wed, 21 Oct 2026 14:00:14 +0000</pubDate></item><item><title>[RFC] [VOTE] Throw exception for invalid characters in number base functions</title><link>https://externals.io/message/132888</link><description>&lt;p&gt;Hi CHU Zhaowei,&lt;/p&gt;
&lt;p&gt;Thank you for your explanation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’ve voted against on this RFC, and the only reason is the choice of a generic \Exception.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, this is fair. A more specific exception is desirable, but currently not easy to get right. Throwing a generic Exception now makes it possible to change this later to something more specific.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;InvalidArgumentException&lt;/code&gt;, which was the exception originally agreed upon, wasn’t brought up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I would have preferred it if you brought this up during the discussion phase.&lt;/p&gt;
&lt;p&gt;InvalidArgumentException is definitely the incorrect exception to use. First, because it is documented as indicating that the argument is not of the expected &lt;em&gt;type&lt;/em&gt;. Second, because it extends from LogicException, which indicates a programming error. Having these function fail is not necessarily programming error, it could be unexpected user input. This was also the argument Tim made against ValueError.&lt;/p&gt;
&lt;p&gt;During the discussion phase, Lazare suggested UnexpectedValueException, which is also an SPL exception and also not semantically correct. So while InvalidArgumentException specifically was not discussed, there was some talk about more specific exceptions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SPL exceptions shouldn’t be thrown from ext/standard. If that’s the blocker, I’d rather see it resolved&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, the SPL exceptions are now of limited use and partially overlap with other things such as ValueError. I would think there would already be an exception I could reuse for the simple case where an argument cannot be processed, but apparently not. The transitions to namespaces and exceptions just has not progressed that far. If you have any suggestion to improve the situation, please let us know.&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;
&lt;p&gt;Sjoerd&lt;/p&gt;
</description><guid>9c2a2889-b4fe-459f-886c-d9b563bcaab2@app.fastmail.com</guid><pubDate>Wed, 21 Oct 2026 13:32:18 +0000</pubDate></item></channel></rss>
