On 10/12/2025 16:23, Tim Düsterhus wrote:
That sentence you quoted was specifically in the context of the
initial paragraph of that section, contrasting PHP - where block
scoping is expected to be used comparatively sparingly - against
languages where variable declarations are a more “bread and butter”
part of the development process, because formally / explicitly
declaring variables is a necessity for one reason or another.
I don't think that changes anything I said in my previous reply: as soon
as you declare a variable half-way through a block, there is an
ambiguity about its range of visibility. Having more variable
declarations makes that *more* likely to come up, not *less*, so I'm not
sure why you think it "avoids" the problem.
There's also an assumption that if PHP added block scoping, it would
only rarely be used. We have no way to know, but I'm not sure that's
true. I can easily imagine code styles adding a rule that all local
variables be declared at an appropriate level. I can also imagine new
users coming from other languages - particularly JS - adding "let" out
of habit, even if seasoned PHP coders wouldn't.
I feel that the C99 requirements and syntax would still have more
ambiguity compared to the proposed `let()` syntax in cases like this:
{
let $foo = bar($baz); // What is $baz referring to?
Particularly if it is a by-reference out parameter.
let $baz = 1;
}
Probably the simplest solution is to re-use our existing definition of
"constant expression". In fact, we already have variable declarations
using that rule:
function foo() {
static $a = 1; // OK
static $b = $a; // Fatal error: Constant expression contains
invalid operations
}
As an example, is a goto jump label a statement?
{
let $foo = 1;
label:
let $bar = $foo++;
goto label;
}
PHP already limits where "goto" can jump to; I don't know how that's
implemented, but I don't think we need to get into philosophical
definitions to say "you can't jump into the middle of a declaration list".
Or, we could just bite the bullet and answer the "which way does it
resolve" question, as loads of other languages have already done.
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
--
Rowan Tommins
[IMSoP]