Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:129627 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id C1EF61A00BC for ; Tue, 16 Dec 2025 21:41:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1765921280; bh=9ons49ann8egM3NKQ+NpLKeUkyZx6RkrRnzeQhB9xMs=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=JOtiYoh+2gPAtcXfbRDc7MEYrb+zdtnOmrNWTsSQdS4pvYt/v12BRD0fZxSzCPZ/J 9pIdoqDgp0NNxC2C+WP8qlMCiy1HVWVlswCkSvJad2K8K4kFueXHgNnWwYSGYRkBH3 Bli/iKnKgeV+4xr2l+3raGdJrfci19K2EM+HrRmRgXA8+JvI+nikx8x2JHiuajI+Gn yKxQcmgYU79vQ8lYEoanUXxComP5dWsYHMPxSpfpO8zKYNq13PJd89Oak1cxIGGjup rxf4mGqPhgAdnOqdRrrPpQ3s1gNwFa7kR5uDW1c3MbvBdYgy5eL0jTVJriSpTNiBDN /HY2BoSdT7FbA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id F2CCB1801D4 for ; Tue, 16 Dec 2025 21:41:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-lj1-f174.google.com (mail-lj1-f174.google.com [209.85.208.174]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 16 Dec 2025 21:41:08 +0000 (UTC) Received: by mail-lj1-f174.google.com with SMTP id 38308e7fff4ca-37a2dcc52aeso46483231fa.0 for ; Tue, 16 Dec 2025 13:41:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1765921262; x=1766526062; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=r9vXwDIBlg6xxMf3Yt4RUQJgnx8viEu03Yr7SmI7KUA=; b=Sy+/Z4Hg521UGvS5t1yyr8dDSx0PkLeKY492XM2KV6/d30XXrxkoNJrvpvjCmA2clL nttzw6XbvH1Nx8ObhuzNqoOQCiO6WfvppwSOK/HbkyMre1KI6tH6wkA2zMfbfix3Xh8W TP+oh+u/EDlNKDGdHEgZBQ4pKUT5gy+rGaLk2vZz3lh5tWib67QUt75MGlKNCdfGVpnq YmtEsMxMEgMXm0LTivVbybSRugYaUyUsJ6kDU4GpyqEtU3JqXcV5cetKVs2olLErG0PN DE4kDfNiVaAAX9+yzJgzZczNizb8e6YP2q60/4Oxjs+X/Gn+lDWJ9xz6H0ntACiOrU8I /JiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765921262; x=1766526062; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=r9vXwDIBlg6xxMf3Yt4RUQJgnx8viEu03Yr7SmI7KUA=; b=aUphOkLFhPUv6RqEzN/9sMOdFeuF0jvTL9jFTq1fEGeOvrTyXRmv+1nT6T+IJOrYQq ojoT9YF6xdd8dwvnapyInSG8/qv3cAb4STCjY0577ADff1V/yWQtZPxWYQBm0xRN8xTt XB8mCqWtT4shDrk+N8CJEtH2ifdIcIE1Kj3TVwL0/4nsoYwp8s5/778HjWLfBkXpfsHB MRVP0saE552VqPDXS49o4ywDKjMEvOUrcaJRjrUbisC1CnswbaxRRA2J9QmsWkw25Tht U0G9IjAYIHcLPLqrYlxfkLEJ0wQMGoaoT4CF7rYjUemJ9SHBQmkeXRwY5NIVRo84FqgF F9oA== X-Gm-Message-State: AOJu0Yw9JTAMR76xCiL2LbebzGUnppICyVpNohxeeAJrY7uxS0lPrQUw E9D/TaMvFJwNeJIkGGAJ1oS37yPpzfMBUCSnyZhYq3X9VtyiT4BK9b5khB6HgQTD89Dfd2hQYxj RCjqiwK1xdOoMeHt78mNAtJUyZeu2VsAv30lq X-Gm-Gg: AY/fxX4yTdMQom+4AbZTEYRmnDL79wKEVr+kimoF6zN4DRfl3WwhI8cC2BYPqFjfzxH 5Y65frNgv4PokKHE2mjN/C1xDNGMGaXJHY4DAMkfZh6kqBT++w2Qh814vRNdDtf2zsepEaZXxRV 79QCk0KbSIrKLjIil+gj8cC3mn5W47mFXONWfgGLPLI7MFbTRfiwinZdCUrs4LigoTma7Yy0STN 7VkU5NZfXo0SdIf5JvKBfbr0W2cHFnmOQG4KMldneM9LC4awW08kXeJ3JGQdU3aX3FD5sYoD7eI mBAM X-Google-Smtp-Source: AGHT+IFZSMyZp0IvIq/07RQI9HxFN3+jMFM9L0J0estzHas0zO6uMOIfkIIoCpssKnSSqRfhvJOlGGZVEl+sT7+SiMY= X-Received: by 2002:a2e:be84:0:b0:37b:a981:102c with SMTP id 38308e7fff4ca-37fd07babbemr48651121fa.18.1765921261467; Tue, 16 Dec 2025 13:41:01 -0800 (PST) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: <70A79513-5503-467E-BC6F-2B0494A3EBB9@benramsey.com> In-Reply-To: Date: Tue, 16 Dec 2025 15:40:49 -0600 X-Gm-Features: AQt7F2rtA4Rz1JWe1SnrEWFkeUc2PoCwetguu8FR_dNFeK9n0sx_YVKBbhUkquA Message-ID: Subject: Re: [PHP-DEV] [RFC] Context Managers To: Larry Garfield Cc: php internals Content-Type: multipart/alternative; boundary="0000000000007dba830646189553" From: mweierophinney@gmail.com ("Matthew Weier O'Phinney") --0000000000007dba830646189553 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, Dec 16, 2025 at 10:01=E2=80=AFAM Larry Garfield wrote: > On Tue, Dec 16, 2025, at 5:25 AM, Deleu wrote: > > On Tue, Dec 16, 2025 at 5:10=E2=80=AFAM Rowan Tommins [IMSoP] > > wrote: > >> (Replying to a few of you in one go, I hope the formatting is clear) > >> > >> >>> we have changed the RFC to use =3D> instead. So the new syntax is > >> >>> > >> >>> using (new CM() =3D> $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 =3D> we have. > >> > > >> > I agree with Matthew. > >> > > >> > I think it makes more sense to reverse them, like this: > >> > > >> > using ($cVar =3D> 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 "=3D". > >> > >> > >> >I also agree with Matthew but the reversed proposed here looks very > very > >> >awkward to me. I think the most natural thing is the =E2=80=9Cas=E2= =80=9D 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(ne= w > 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 =3D ne= w > > 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.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 `=3D>` for > this. > > > > In an array, `=3D>` is an assignment of key/value pairs. > > For foreach ($iterator as $key =3D> $value), the =3D> 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 () =3D>`. 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 `=3D>` is the THEN. > > > > My conclusion is that `=3D>` is either a value placement (for arrays) o= r > > an instruction execution (for arrow function and match). As such, If = =3D> > > were to be incorporated into Context Managers, I think it would make > > much more sense like this: > > > > `using (new ContextManager as $context) =3D> [single line expression]` > > where the arrow creates a symmetry with how arrow functions work. > > > First, yeesh, where were y'all 2 weeks ago? :-P > > Second, I find it fascinating that there's so many different > mutually-incompatible spins on what =3D> means. As argued in the > short-functions and auto-capture-closure RFCs from a few years ago, =3D> = in > nearly all cases currently means "evaluates to." > > $arr =3D [ > 'a' =3D> 'A", > 'b' =3D> 'B', > ]; > > $arr['a'] // This "evaluates to" A > > match ($foo) { > 'a' =3D> 'A', > 'b' =3D> 'B', // The 'b' case "evaluates to" B > }; > > fn($foo) =3D> 'bar'; // This function "evaluates to" bar > > foreach ($arr as $k =3D> $v) {} > > The last is a little bit inconsistent, but can still be read as "$k, and > the thing that $k evaluates to." > This is not at all how I read it. "evaluates to" is an assignment, and assignments in PHP flow right to left. In the case of an array, if I access the "a" key above, I get the value "A". For your match example, if the match applies to "a", I get the value "A". For an arrow function, I get the callable with the return. In other words, the expression on the right is either evaluated or assigned to the thing on the left. With the proposed syntax, "using ($expression =3D> $variable) { ... }", th= is reads backwards: the expression is now on the left, and is captured to the thing on the right. That's what I'm saying will be confusing. > > So given that, and as Rowan noted the context manager is *NOT* the contex= t > variable: > > using ($cm evaluates to $cv) {} > > That's the meaning we're going for. > And again, that doesn't make sense from typical assignment rules. This is why the other proposal's syntax ("let ($var =3D expression)") is not having the same debate - the syntax is consistent with existing usage. It's also consistent with how other scripting languages handle block scoping of variables (see JS, shell scripting). > > If there's some better word than =3D>, we're still open to it, but I am > going to insist on left-to-right reading. $cm is created first, then it > produces $cv. > > 'as' is what we had originally, since that's what Python used. However, > it was pointed out that it was confusing as it implied the CM and CV were > the same thing, or rather the expression on the left gets assigned to $cv= , > which is not the case. Hence the change. > I didn't find it ambiguous, but I can see where others might. That said, I found it _less_ ambiguous than =3D> here. > > A symbol does have the (dis?)advantage of a somewhat squishier meaning > than a keyword. > > I want block scoping; I have been bitten by accidental re-assignment within a block many times, and hate having to come up with an ever-so-slightly-different variable name to disambiguate. I don't care if it's this proposal or the "let" proposal in terms of how the engine handles it - but the syntax of "using (expression =3D> $var)" isn't going to get my vote due to how easily it can be written incorrectly. I have no problem with the "using (expression as $var)" syntax, and the "let($var =3D expression) syntax is just fine for me as well. --=20 Matthew Weier O'Phinney mweierophinney@gmail.com https://mwop.net/ he/him --0000000000007dba830646189553 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


On Tue, Dec 16,= 2025 at 10:01=E2=80=AFAM Larry Garfield <larry@garfieldtech.com> wrote:
On Tue, Dec 16, 2025, at 5:25 AM, Deleu w= rote:
> On Tue, Dec 16, 2025 at 5:10=E2=80=AFAM Rowan Tommins [IMSoP]
> <imsop.ph= p@rwec.co.uk> wrote:
>> (Replying to a few of you in one go, I hope the formatting is clea= r)
>>
>> >>> we have changed the RFC to use =3D> instead.=C2=A0= So the new syntax is
>> >>>
>> >>> using (new CM() =3D> $cVar) {
>> >>>=C2=A0 =C2=A0// Do stuff here.
>> >>> }
>> >>>
>> >>
>> >> Going to be controversial here, but this is confusing, be= cause it operates
>> >> in the exact opposite of every other usage of =3D> we = have.
>> >
>> > I agree with Matthew.
>> >
>> > I think it makes more sense to reverse them, like this:
>> >
>> >=C2=A0 =C2=A0 =C2=A0using ($cVar =3D> new CM()) {
>> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// Do stuff here.
>> >=C2=A0 =C2=A0 =C2=A0}
>>
>>
>> It took me a long time to figure out what you were both saying her= e, 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 "=3D= ".
>>
>>
>> >I also agree with Matthew but the reversed proposed here looks= very very
>> >awkward to me. I think the most natural thing is the =E2=80=9C= as=E2=80=9D 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'v= e said in a few places, a Context Manager is like an iterator that goes aro= und once.
>>
>>
>> > That seems symmetrical to using (new Manager as
>> >$manager) where the instance (left) is assigned to the variabl= e (right).
>>
>>
>> This, however, is why it was changed: that is *not* what is happen= ing. The Context Manager is not assigned to the variable, it *produces a va= lue* which is assigned to the variable.
>>
>> Again, look at the foreach equivalence: you wouldn't write &qu= ot;foreach(new MyIterator as $iterator)", because it's not the ite= rator that ends up in the variable, it's the *items produced by* the it= erator.
>>
>> 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 mentio= ned
> `foreach(new MyIterator as $iterator)` is not how it works. An iterato= r
> *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 = =3D 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.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 <= br> > 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 rea= d at all
>
> - `for one(new ContextManager as $context)`
> Kind of implies it works with iterators (similar to each), which is no= t
> 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 <= br> > 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 `=3D>` f= or this.
>
> In an array, `=3D>` is an assignment of key/value pairs.
> For foreach ($iterator as $key =3D> $value), the =3D> is a destr= ucting
> instruction that aligns with how the array was originally assigned. > For the arrow function, it's kind of implied in the name ARROW fun= ction
> that we would need a syntax in the lines of `fn () =3D>`. 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 `=3D>` is the THEN.
>
> My conclusion is that `=3D>` is either a value placement (for array= s) or
> an instruction execution (for arrow function and match). As such, If = =3D>
> were to be incorporated into Context Managers, I think it would make <= br> > much more sense like this:
>
> `using (new ContextManager as $context) =3D> [single line expressio= n]`
> where the arrow creates a symmetry with how arrow functions work.
<= br>
First, yeesh, where were y'all 2 weeks ago? :-P

Second, I find it fascinating that there's so many different mutually-i= ncompatible spins on what =3D> means.=C2=A0 As argued in the short-funct= ions and auto-capture-closure RFCs from a few years ago, =3D> in nearly = all cases currently means "evaluates to."

$arr =3D [
=C2=A0 'a' =3D> 'A",
=C2=A0 'b' =3D> 'B',
];

$arr['a'] // This "evaluates to" A

match ($foo) {
=C2=A0 'a' =3D> 'A',
=C2=A0 'b' =3D> 'B', // The 'b' case "evalu= ates to" B
};

fn($foo) =3D> 'bar'; // This function "evaluates to" b= ar

foreach ($arr as $k =3D> $v) {}

The last is a little bit inconsistent, but can still be read as "$k, a= nd the thing that $k evaluates to."

This is not at all how I read it. "evaluates to" is an assignme= nt, and assignments in PHP flow right to left.=C2=A0

In the case of an array, if I access the "a" key above, I get = the value "A". For your match example, if the match applies to &q= uot;a", I get the value "A". For an arrow function, I get th= e callable with the return. In other words, the expression on the right is = either evaluated or assigned to the thing on the left.

=
With the proposed syntax,=C2=A0 "using ($expression =3D> $vari= able) { ... }", this reads backwards: the expression is now on the lef= t, and is captured to the thing on the right. That's what I'm sayin= g will be confusing.

So given that, and as Rowan noted the context manager is *NOT* the context = variable:

using ($cm evaluates to $cv) {}

That's the meaning we're going for.

=
And again, that doesn't make sense from typical assignment rules. = This is why the other proposal's syntax ("let ($var =3D expression= )") is not having the same debate - the syntax is consistent with exis= ting usage. It's also consistent with how other scripting languages han= dle block scoping of variables (see JS, shell scripting).

If there's some better word than =3D>, we're still open to it, b= ut I am going to insist on left-to-right reading.=C2=A0 $cm is created firs= t, then it produces $cv.

'as' is what we had originally, since that's what Python used.= =C2=A0 However, it was pointed out that it was confusing as it implied the = CM and CV were the same thing, or rather the expression on the left gets as= signed to $cv, which is not the case.=C2=A0 Hence the change.

I didn't find it ambiguous, but I can see where = others might. That said, I found it _less_ ambiguous than =3D> here.=C2= =A0

A symbol does have the (dis?)advantage of a somewhat squishier meaning than= a keyword.

I want block scoping; I have been bitten by acciden= tal re-assignment=C2=A0within a block many times, and hate having to come u= p with an ever-so-slightly-different variable name to disambiguate. I don&#= 39;t care if it's this proposal or the "let" proposal in term= s of how the engine handles it - but the syntax of "using (expression = =3D> $var)" isn't going to get my vote due to how easily it can= be written incorrectly.

I have no problem with th= e "using (expression as $var)" syntax, and the "let($var =3D= expression) syntax is just fine for me as well.=C2=A0

= --
Matthew Weier O'Phinney
<= a href=3D"mailto:mweierophinney@gmail.com" target=3D"_blank">mweierophinney= @gmail.com
https://m= wop.net/
he/him
--0000000000007dba830646189553--