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

Reply via email to