Re: [RFC] Context Managers

From: Date: Tue, 16 Dec 2025 11:25:03 +0000
Subject: Re: [RFC] Context Managers
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to internals+get-129620@lists.php.net to get a copy of this message
On Tue, Dec 16, 2025 at 5:10 AM Rowan Tommins [IMSoP] <imsop.php@rwec.co.uk> wrote: > (Replying to a few of you in one go, I hope the formatting is clear) > > >>> we have changed the RFC to use => instead. So the new syntax is > >>> > >>> using (new CM() => $cVar) { > >>> // Do stuff here. > >>> } > >>> > >> > >> Going to be controversial here, but this is confusing, because it > operates > >> in the exact opposite of every other usage of => we have. > > > > I agree with Matthew. > > > > I think it makes more sense to reverse them, like this: > > > > using ($cVar => new CM()) { > > // Do stuff here. > > } > > > It took me a long time to figure out what you were both saying here, > because to me the direction of the arrow seems to consistently indicate > data flow: you call the function, and data comes out; you enter the > context, and a variable comes out. > > But I think I see it now: you're treating the context variable like an > array key, that is somehow "bound to" the result. Except that's not what's > happening, otherwise we could just use "=". > > > >I also agree with Matthew but the reversed proposed here looks very very > >awkward to me. I think the most natural thing is the “as” but I may have > >missed the discussion on why it had to be changed. > > > >Thinking of foreach ($array as $value), an item from the array (left) is > >assigned to $value (right). > > > This is the way to read the "as" syntax, yes; as I've said in a few > places, a Context Manager is like an iterator that goes around once. > > > > That seems symmetrical to using (new Manager as > >$manager) where the instance (left) is assigned to the variable (right). > > > This, however, is why it was changed: that is *not* what is happening. The > Context Manager is not assigned to the variable, it *produces a value* > which is assigned to the variable. > > Again, look at the foreach equivalence: you wouldn't write "foreach(new > MyIterator as $iterator)", because it's not the iterator that ends up in > the variable, it's the *items produced by* the iterator. > > So you have "foreach(new MyIterator as $item)" and "using(new > MyContextManager as $contextVar)". > > But evidently that is not obvious to readers. > My conclusion here is exactly the opposite of yours because this explanation makes as even more symmetrical now. As you've mentioned foreach(new MyIterator as $iterator) is not how it works. An iterator *produces a value* that is assigned to the variable after as. Symmetrically, using(new ContextManager as $context) the ContextManager is also producing a value that is assigned to the variable after as. The only difference is in the keyword: foreach will loop, but using will not loop since ContextManager is not an iterator. I'm assuming this would also be a valid syntax: `using ($manager = new ContextManager as $context)` which gives us a shot at capturing the context manager. I wrote a little snippet to try and see (using GitHub Gist Syntax Highlighter) how some of the options would look like once IDE support / syntax highlighting is baked in: [image: image.png] Ultimately, people will take a quick reading in a Context Manager documentation and the parallels to explain how it works seems to be very well in place for as, imo. In the image above I tried adding for using because I was trying really hard to come up with a word that could replace each in foreach to make it even more symmetrical, but I could not find anything decent. - for context(new ContextManager as $context) This one reads well, but the fact its two words (and a long word for that matter) doesn't sit well. - for with(new ContextManager as $context) I'm not a native English speaker, but I think this doesn't read at all - for one(new ContextManager as $context) Kind of implies it works with iterators (similar to each), which is not exactly the case and the language has very little motivation to create an iterator that loops only once just to make this work. - for using(new ContextManager as $context) Similar thoughts as for context, the only difference that makes me like this one more is because for context doesn't sit well with try context while for using could go well with try using. In any case, the longer I sit with this the more I dislike => for this. In an array, => is an assignment of key/value pairs. For foreach ($iterator as $key => $value), the => is a destructing instruction that aligns with how the array was originally assigned. For the arrow function, it's kind of implied in the name ARROW function that we would need a syntax in the lines of fn () =>. I don't think this relates well with arrays, but it works well to me because of how universal arrow functions are in Javascript. For match ($value), it reads as `WHEN ($value) MATCH '' THEN. The arrow here => is the THEN. My conclusion is that => is either a value placement (for arrays) or an instruction execution (for arrow function and match). As such, If => were to be incorporated into Context Managers, I think it would make much more sense like this: using (new ContextManager as $context) => [single line expression] where the arrow creates a symmetry with how arrow functions work. -- Marco Deleu

« previous php.internals (#129620) next »