Re: [RFC] Scope

From: Date: Wed, 11 Nov 2026 15:03:31 +0000
Subject: Re: [RFC] Scope
References: 1 2 3 4 5  Groups: php.internals 
Request: Send a blank email to internals+get-133076@lists.php.net to get a copy of this message
On Tue, Nov 10, 2026, at 6:46 AM, Frode Børli wrote: > Hi Côme, > >> If suddenly scope starts to clear headers, ini_set or whatever, all existing code using it >> will break? > > Nothing is cleared, in this RFC or in a later one. When a piece of > state follows the scope, each scope has its own instance of it. The > root scope keeps the process state exactly as it is today, so code that > never creates a scope, which is all code written before this RFC, sees > no change, now or later. > > Code that runs inside a non-root scope is also meant to keep working as > it does today. That is one of the purposes of Scope: legacy code should > keep working in a long-running server without being rewritten. Take > vote B: code that calls Locale::setDefault() for user X and later > Locale::getDefault() does so within one request, and both calls happen > in the same scope, so it gets the locale it set. What changes is that a > request for user Y, running in another scope, no longer sees X's > locale. From the point of view of the code, nothing changed; it just > stopped being affected by other requests. > > The reason this holds is where scopes are switched. Code does not > switch scope while it is processing one request. Scopes are switched > between requests, by the SAPI or the application server, which is also > the party that has the request to put into the new scope. The parallel > work a request starts stays in the request, through fibers, which > follow the scope. Larry's legacyLogic() example creates a scope in the > middle of a request and then expects the request's data to still be > there; that is not what run() is for, and I'll make that more explicit > in the RFC. > > Each later move is still its own RFC, with its own BC section and vote; > the Future Scope list states the direction, so that servers and > frameworks creating scopes know it before they write that code. What > this RFC fixes now is the rule they would all follow: a scope has its > own instance of the state that follows it, and the root keeps what the > process has today. > > Best regards, > Frode Børli I think there's an implicit assumption you're making here that is not safe to make. Specifically, you're focused on the request scope use case. I agree, that's the most obvious place for it to apply, and the likely most common. And the 2-3 libraries that make a request scope (FrankenPHP, Revolt, Swoole, etc.) that other people build off of can probably be expected to get it right (for whatever "right" means). However, there is nothing in the design of the RFC that limits it to being used just for the request, and only by a select number of very careful projects. It can be created by literally anyone, anywhere, at any time, whether we think it's a good idea or not. Which means I can guarantee it *will* be created by someone, somewhere, at some time that is bad idea, and sloppily. So literally any function that reads the super globals today *could* end up in a scope created by someone other than FrankenPHP that doesn't manually clone the superglobals, and therefore will break. That it's not a responsibly created request-bound scope is irrelevant, because not all scopes will conform to that lifecycle. The same applies for any other "ambient state" that becomes scope-aware. If the pattern is that a new Scope starts with a blank ambient state, and it's the caller's job to populate it, then every time new parts of the ambient state become scope-aware, the required manual setup code changes. That creates a BC break every single time more ambient state is added. That simply won't fly. Instead, if the scope-aware ambient state starts as a clone of the originating scope, then in most cases code doesn't care. That it's now working with a copy of $_GET, or a scope-bound default locale, or scope-bound default timezone is irrelevant in the 99% case. But it shouldn't have to deal with "whelp, someone made a new scope 40 function calls up the stack, so now the ambient state is missing." Missing ambient state is a fatal waiting to happen. Even then, there's still a small BC concern if some existing code is setting the ambient state, and expecting it to persist for the entire process lifetime instead of just the current scope lifetime. However, the surface area for that is orders of magnitude smaller than "All code needs to consider that $_GET might not be set at all now, sorry." This is a landmine large enough that it would keep me from supporting this RFC, which I otherwise quite like. --Larry Garfield

« previous php.internals (#133076) next »