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