Re: [RFC][Discussion] use construct (Block Scoping)

From: 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

« previous php.internals (#129599) next »