Re: [RFC] Context Managers, v2

From: Date: Wed, 11 Nov 2026 14:46:12 +0000
Subject: Re: [RFC] Context Managers, v2
References: 1 2  Groups: php.internals 
Request: Send a blank email to internals+get-133075@lists.php.net to get a copy of this message
On Tue, Nov 10, 2026, at 5:32 AM, Côme Chilliet wrote: > Hello, > > Le jeudi 5 novembre 2026, 18:33:14 heure normale d’Europe centrale > Larry Garfield a écrit : >> Hi folks. Based on the feedback and problems with the previous Context Managers RFC, >> Arnaud and I have a new approach to present: >> >> https://wiki.php.net/rfc/context-managers-v2 >> >> It basically swaps the two-method approach in favor of "it's a generator, >> you're welcome." The result is, I think, both simpler and more flexible, and resolves a >> number of other issues as well. More details in the RFC. >> >> There is a linked implementation, though Arnaud warns it's only partially complete so >> go easy on it. :-) But the design in the RFC is all ready for review. > > I do not understand this sentence: «Additionally, it is legal for a > Context Manager object to return $this as the context variable if that > is appropriate in the specific use case.» > If ContextManager::getContextManager returns $this, which Generator is > used 🤔 That should read "yield $this". Like so: class Foo implements ContextManager { public function getContextManager(): \Generator { yield $this; { } In which case the context variable will be an instance of Foo. I'll adjust the language. > The whole section «Mixing with try-catch» is also a mystery to me. I do > not understand why "using" would need a short syntax for try catch any > more than any other keyword we often put in a try/catch, nor what the > explanations in there mean. As stated in the RFC, we expect doing this to be very common: function something(): \Generator { try { $something = init_something(); yield $something; } finally { deinit($something); } } try { using (something() => $var) { // Do stuff with $var. }; } catch (\Exception $e) { // Additional error handling, but we don't need to clean up $something.. That's already handled. } So the short-hand form just lets us reduce the nesting a bit for a common case. One could make an argument that we could support arbitrary single-expression try statements this way; I'd be open to that myself, but that's out of scope for this RFC. > Is the semi-colon necessary after the closing '}' ? That reads weird, > it’s not clear to me why it’s not a single '}' like after an if or > foreach or whatever. Because using() is an expression, like match() or an anonymous function. Those have semicolons after them as well, because they're not a complete statement, just an expression. The same applies here. > Also, this semi-colon is missing in at least one example. Which one? > In the transaction example, $conn does not exist, I suppose both > instances should be $this? You are correct, fixed. Thanks. > «A return statement inside the BODY will return from the function the > code is currently executing in. A finally block in the generator > context manager will still be executed, but otherwise control returns > to the function's caller.» > This is also hard to get for me. > Can you detail what this would output: > function context(): \Generator { > echo "A\n"; > yield "B"; > echo "C\n"; > return "D"; > } > var_dump( > using (context() => $c) { > echo "E\n"; > return "F"; > } > ); I believe (without actually running it) that would output: A E The return "F" terminates the function that the var_dump()/using() construct is in. The generator is discarded without ever reaching its end, so the generator's return statement is never reached. That said, you have brought up an interesting question, I have no idea what happens when you var_dump() a compound expression like this that returns. Something for Arnaud to write tests for. 0:-) --Larry Garfield

« previous php.internals (#133075) next »