You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since PHP 8.0, the unpack/spread operator ...$iterable can be used with either int or string keys, with integers mapped to positional parameters (regardless of value) and strings mapped to named parameters.
With an iterator, it's possible to return a numeric string key which could not exist in a normal array. In the simple case, this leads to an error such as "Unknown named parameter $0" https://3v4l.org/IQBdd
When combined with a variadic parameter, the behaviour becomes rather more peculiar: the key is collected into the variadic parameter, even if there are other positional parameters left to fill; and the key is left as a string, even though any other context would force it to an int.
I can think of two sensible behaviours here:
Normalise numeric string keys coming back from the iterator during the spread operation, and assign them to positional, rather than named, parameters. This would mean that yield '0' => 'foo'; gives the same behaviour as yield 0 => 'foo';, and that spreading into arguments behaved the same ways as spreading into an array.
Forbid any string key which would not be valid as a parameter name, including numeric strings. Right now, it's possible to include any character you like in the key, with potentially dangerous side-effects (see below).
Casess a() and b() populate the positional parameters $x and $y with "first" and "second", and "third" is treated as the first variadic argument, with key 0. When given an iterator with string keys, all four items are collected, and the keys are not normalised, resulting in this broken array:
An additional check could be made using php_valid_var_name: https://heap.space/xref/php-src/ext/standard/array.c#php_valid_var_name (This is the function used by extract, which in its default mode silently discards anything with an invalid variable name; as far as I know, the rules for parameter names are the same as those for variable names.)
Description
Since PHP 8.0, the unpack/spread operator
...$iterable
can be used with either int or string keys, with integers mapped to positional parameters (regardless of value) and strings mapped to named parameters.With an iterator, it's possible to return a numeric string key which could not exist in a normal array. In the simple case, this leads to an error such as "Unknown named parameter $0" https://3v4l.org/IQBdd
When combined with a variadic parameter, the behaviour becomes rather more peculiar: the key is collected into the variadic parameter, even if there are other positional parameters left to fill; and the key is left as a string, even though any other context would force it to an int.
I can think of two sensible behaviours here:
yield '0' => 'foo';
gives the same behaviour asyield 0 => 'foo';
, and that spreading into arguments behaved the same ways as spreading into an array.Here's an example: https://3v4l.org/jOddJ
Casess
a()
andb()
populate the positional parameters$x
and$y
with "first" and "second", and "third" is treated as the first variadic argument, with key0
. When given an iterator with string keys, all four items are collected, and the keys are not normalised, resulting in this broken array:It is even possible to end up with both
0
and"0"
as keys in the same array: https://3v4l.org/qNMepResults in:
While writing this up, I realised that as well as numeric keys from iterators, even array spreading can be abused in potentially dangerous ways.
Newlines: https://3v4l.org/QfRmi
Null bytes: https://3v4l.org/XLC8M
PHP Version
Operating System
No response
The text was updated successfully, but these errors were encountered: