On 19/10/2022 18:04, David Rodrigues wrote:
It seems to me to be a reasonable problem and one that needs attention, as
the message is not that "compact cannot be used here", but that "the
variable does not exist".

I'd just like to point out that the error message here is 100% correct: there is nothing wrong with using compact() inside a closure, it just only has access *at run-time* to the variables which were captured when the closure was created, which are determined *at compile-time*.

$foo = fn() => [$a, compact('a', 'b')];

is essentially compiled to:

$foo = function (use $a) { return [$a, compact('a', 'b')] };

When you later execute $foo, compact() can see the local $a, but there is no $b anywhere in the compiled definition.



On 20/10/2022 08:15, Claude Pache wrote:
Although it is difficult to make it work in general (of course), there is the 
specific case of names given as literal strings, as in the example provided by 
the OP, that does not suffer from the impossibility of static analysis.


While it would be possible for the compiler to special-case this scenario, I think it could be rather confusing to have a function that is sometimes evaluated at compile-time and sometimes at run-time (other than as a transparent performance optimisation). For instance, each of the following *can* be fully evaluated to a constant at compile-time, but which ones would be?

compact('a' . 'b');

$name = 'a';
compact($name);

$x = 1;
compact('a' . $x);

$x = 1;
$x++;
compact('a' . $x);


I think it would be better to look at a new syntax for specifying such arrays that doesn't rely on a run-time function, similar to how in JS  { foo, bar } is short-hand for { foo: $foo, bar: $bar }

This has come up before, for instance in Nikita's discussion of named parameter syntaxes: https://wiki.php.net/rfc/named_params#shorthand_syntax_for_matching_parameter_and_variable_name

As well as removing the need to pass a variable name as a string, this would allow combining explicit and automatic names in one literal, e.g.:

// Current array literal
$x = [ 'foo' => $foo, 'bar' => someFunc() ];

// compact()
$bar = someFunc();
$x = compact('foo', 'bar');

// Shortest variation in Nikita's RFC linked above
$x = [ :$foo, bar: someFunc() ];


I'm personally not a fan of this coding style, because I think variables should be named to be meaningful in the current scope, not somewhere they're coming from or going to, but a dedicated syntax would at least allow that flexibility.

Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to