On Wed, May 6, 2026, at 3:15 PM, Bob Weinand wrote: > Hey Larry, > >> Am 19.01.2026 um 16:58 schrieb Larry Garfield <[email protected]>: >> >> As noted in Future Scope, we can add function-based context managers as well >> based on generators. At the moment we're not convinced it's necessary, but >> it's a straightforward add-on if we find that always writing a class for a >> context manager is too cumbersome. >> >> The issue with punting this behavior to user-space is that a library cannot >> provide this sort of functionality in a clean way. >> >> In an ideal world, if we had auto-capturing long-closures, then I would >> agree this is largely unnecessary and could instead be implemented like so >> (to reuse the examples from the RFC): >> >> $conn->inTransaction(function () { >> // SQL stuff. >> }); >> >> $locker->lock('file.txt', function () { >> // File stuff. >> }); >> >> $scope->inScope(function () { >> $scope->spawn(yadda yadda); >> }); >> >> $errorHandlerScope->run(fn() => null, function () { >> // Do stuff here with no error handling. >> }); >> >> And so forth. If we had auto-capturing closures, I would probably argue >> that is a better approach. >> >> However, auto-capturing closures have been rejected several times, and I >> have no confidence that we will ever get them. (Whether you approve or >> disapprove of that is your personal opinion.) The current alternative >> involves using lots of `use` clauses, which is needlessly clunky to the >> point that folks try to avoid it. >> >> I literally have code like this in a project right now, and I've had to do >> this many times: >> >> public function parseFolder(PhysicalPath $physicalPath, LogicalPath >> $logicalPath, array $mounts): bool >> { >> return $this->cache->inTransaction(function() use ($physicalPath, >> $logicalPath, $mounts) { >> // Lots of SQL updates here. >> }); >> } >> >> That's just gross. :-) This is exactly the example that's been used in the >> past to argue in favor of auto-capturing closures, but it's never been >> successful. > > I fully agree that this is gross. I have just created a comprehensive > RFC https://wiki.php.net/rfc/scope-functions to address this underlying > problem you describe. > > It does address quite a few of the main issues people had with trivial > auto-capturing Closures which would simply clone the symbol table. > > I personally really don't like this Context Managers RFC given the > apparent complexity it has (only for heavyweight usages basically, > library style - you wouldn't just create ContextManager implementing > classes ad hoc for everything). > > Thus, I'd like to ask you to consider my RFC first and give feedback on > it, and possibly - obviously only if you think my RFC is a good choice > for the language - pause this RFC for as long as mine is under > discussion. > > Thanks, > Bob
Hi Bob. I've looked over your RFC, and have a number of issues with it as a Context Manager alternative. For one, I don't see an indication that this one would fair any better than the past several attempts. (Such things are impossible to predict.) So blocking context managers on it seems unwise. Second, the restrictions around where it can be used or passed feel very arbitrary (I realize there's a reason for them, but as a user, it feels arbitrary and confusing), which is also a problem. Third, I know I said above that auto-capturing closures would likely obviate the need for context managers, but Rowan had a valid point in his earlier reply to me that CMs have the advantage of not creating a new scope (not even visually). That makes the behavior of any newly created variables inside the `using` body self-evident: They survive. Closures have done the opposite for 17 years, for reasons that are also self-evident (it's a different function). Having a special type of closure that "leaks" by design is very confusing and not at all obvious, especially when it's a type of closure that seems like it would be generally useful. Fourth, and related, it's self-evident that the `using` block's body is executed immediately in-place, the same way a for, while, or try body would be. A shared-scope closure doesn't have that clarity, and could be executed at any arbitrary time in the future before the defining function terminates. That makes it, well, somewhat reusable, which is again, rather confusing. Fifth, I disagree that CMs are particularly "heavyweight." A 2-method class is hardly a large lift, and at runtime it's just try-catch blocks. Certainly, they will likely be used many more times than they are written, but that's a feature, not a flaw. It's also true of most of PHP, like, interfaces. It's also not particularly shorter; the DB Transaction example, for instance, is still roughly the same number of lines of code in either approach. Just one uses a class, one uses a method. Rowan's subsequent suggestion of a macro system is... highly interesting, but also a very, very deep rabbit hole that would take a lot of time to run down. So at this time we are going to continue with the Context Manager RFC, though I appreciate your effort in finding alternative approaches. One thing it has suggested to me is that it may be worth exploring the generator-based approach that's currently in future scope, as that may offer a bit more flexibility and suggest solutions to the return/throw question. --Larry Garfield
