Re: [RFC][Discussion] use construct (Block Scoping)
| From: | Larry Garfield | Date: | Fri, 12 Dec 2025 21:54:47 +0000 |
| Subject: | Re: [RFC][Discussion] use construct (Block Scoping) | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-129599@lists.php.net to get a copy of this message | ||
On Thu, Dec 11, 2025, at 4:21 PM, Rowan Tommins [IMSoP] wrote:
>> Being able to declare variables with “if” lifetime that I can also
>> check is a big part of the benefits of the proposed syntax and
>> something I'm missing in other languages.
>>
>> if (let $user = $repository->find(1); $user !== null) { }
>
> I find this more readable than the proposed version:
>
>
>> let ($user = $repository->find(1)) if ($user !== null) { }
>
>
> Skimming down a piece of code, I can spot where code is being run
> conditionally without reading the condition itself:
>
> if ............ {
>
> With the proposed syntax, that first glance is:
>
> let ........... {
>
> On closer inspection, it's actually:
>
> let ..... if ..... {
>
>
> Maybe it's also because I've dabbled in Perl, which has post-fix
> conditions, so a very similar line would have a very different meaning:
>
> my $foo=do_bar() if ($baz != 0);
>
> is equivalent to:
>
> my $foo;
> if ($baz != 0) { $foo=do_bar(); }
>
> Which is also a word order we can use in English, e.g. "hang the wet
> clothes inside if it is raining".
>
>
> In terms of making it less of a special case, some languages have a ","
> operator which lets you glue any two expressions together and get the
> right-hand result.
>
> In Perl, you can write this:
>
> ```
> my $a = 'outer', $b = 'whatever';
> if ( my $a='inner', $b == 'whatever' ) {
> say $a; // 'inner'
> }
> say $a; // 'outer'
> ```
>
> This gives the desired scope for $a, but the if statement is still just
> accepting a single expression.
>
> JavaScript has the same operator, but apparently doesn't allow "let" in
> an expression, so you can write:
>
> if ( a="inner", b=="whatever" ) { }
>
> but can't use it to declare a local version of "a".
>
>
> I haven't thought through exactly how to apply that to PHP, but it might
> give us an option for "both and": a concise and reusable syntax for the
> if use case, and a separate syntax for cases like the closure example I
> gave earlier: https://externals.io/message/129059#129075
The more I think on this, the more I think that the auto-unsetting behavior of a
let
would be useful *only* in combination with some other existing block, not as its own block.
if (let $x=stuff(); $x < 1) { ... }
for (let $i = 0; $i < 10; $i++) { ... }
foreach (let $arr as $k =>v) { ... } (applies to both $k and $v)
And so on. (I'm not sure if it makes sense on a while? Possibly.) Exact syntax above is just
spitballing.
But that would allow for the mask/unset logic for variables that have special meaning in existing
block constructs, which is generally what you'd be interested in. I don't think
there's a huge use case for unsetting arbitrary variables in arbitrary places. It would also
be cleaner than the current pattern of if ($x = stuff() && $x < 1) {}, which always felt
clunky and "leaks" $x.
If you need some thing more arbitrary and custom than cleaning up an existing block construct, then
the additional setup of a Context Manager is fully justified, and more robust.
--Larry Garfield