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