Hello!
With PHP8 released and the named arguments RFC being implemented, there's
now an inconsistency in how the spread operator works.
Historically, the spread operator was first used in PHP 5.6 for arguments:
function php56($a, $b) {
return $a + $b;
}
$test = [1, 2];
php56(...$test) === 3;
Then, with PHP 7.4, the spread operator was also introduced for array
literal syntax:
$parts = ['apple', 'banana'];
$fruits = ['strawberry', ...$parts, 'grape'];
$fruits == ['strawberry', 'apple', 'banana', 'grape'];
The RFC back then explicitly excluded 1 string keys, to make the
functioning of the spread operator consistent with how it's used for
function arguments.
Now, in PHP8 we can do:
function php8(int $a, int $b): int {
return $a + $b;
}
$test = ['b' => 40, 'a' => 2];
php8(...$test) === 42;
However, string keys in array literals are still not possible. So the
limitation that once was introduced for consistency now led to an
inconsistency.
I suggest to allow string keys to also be used in array literals:
$template = ['created_at' => time()
, 'is_admin' => 1];
$db_rows = [
['name' => 'Alice', 'email' => 'alice@example.org', ...$template],
['name' => 'Bob', 'email' => 'bob@example.org', ...$template],
];
What's your feedback on that? Do you see any obvious problems with that
approach? I searched through the archives and couldn't find this problem
being mentioned before.
-Florian
On Wed, 2 Dec 2020 at 17:24, Florian Stascheck florian.stascheck@gmail.com
wrote:
Hello!
With PHP8 released and the named arguments RFC being implemented, there's
now an inconsistency in how the spread operator works.Historically, the spread operator was first used in PHP 5.6 for arguments:
function php56($a, $b) {
return $a + $b;
}
$test = [1, 2];
php56(...$test) === 3;Then, with PHP 7.4, the spread operator was also introduced for array
literal syntax:$parts = ['apple', 'banana'];
$fruits = ['strawberry', ...$parts, 'grape'];
$fruits == ['strawberry', 'apple', 'banana', 'grape'];The RFC back then explicitly excluded 1 string keys, to make the
functioning of the spread operator consistent with how it's used for
function arguments.Now, in PHP8 we can do:
function php8(int $a, int $b): int {
return $a + $b;
}
$test = ['b' => 40, 'a' => 2];
php8(...$test) === 42;However, string keys in array literals are still not possible. So the
limitation that once was introduced for consistency now led to an
inconsistency.I suggest to allow string keys to also be used in array literals:
$template = ['created_at' =>
time()
, 'is_admin' => 1];
$db_rows = [
['name' => 'Alice', 'email' => 'alice@example.org', ...$template],
['name' => 'Bob', 'email' => 'bob@example.org', ...$template],
];What's your feedback on that? Do you see any obvious problems with that
approach? I searched through the archives and couldn't find this problem
being mentioned before.-Florian
The reason why this has been deferred is because of which semantics should
be used for duplicate string keys.
Do we use the addition between two arrays semantics or the array_merge()
semantics? See: https://3v4l.org/7QbWv
As the previous RFC you linked initially wanted to use the array_merge()
semantics. But due to contention was left out.
Best regards,
George P. Banyard
The reason why this has been deferred is because of which semantics should
be used for duplicate string keys.Do we use the addition between two arrays semantics or the
array_merge()
semantics? See: https://3v4l.org/7QbWv
array_merge is the only one that makes sense. Addition of positional
arrays is nonsensical:
[1,2,3] + [4,5,6] ===> [1,2,3]
As for named keys, every other language with a similar construct
(perl, python, javascript) uses array_merge semantics. Truth is I'm
sorely disappointed that + works like it does, but there's no fixing
it now.
--c
The reason why this has been deferred is because of which semantics should
be used for duplicate string keys.Do we use the addition between two arrays semantics or the
array_merge()
semantics? See: https://3v4l.org/7QbWvAs the previous RFC you linked initially wanted to use the
array_merge()
semantics. But due to contention was left out.Best regards,
George P. Banyard
Does the loose interpretation of an array also play into this??
[“string” => true, 10 => false]
Another new-to-internals questions, does the check only look at if the keys contain one that is a string, that they’re all integers (not float), that they’re all sequential??
Cheers,
Josh
Le Wed, 2 Dec 2020 17:45:47 +0000,
"G. P. B." george.banyard@gmail.com a écrit :
The reason why this has been deferred is because of which semantics should
be used for duplicate string keys.
['a' => 1, ...['a' => 2]] should be the same as ['a' => 1, 'a' => 2], I do not
see how any other way would be justifiable.
This means using array_merge semantic, as ['a' => 1, 'a' => 2] evaluates to
['a' => 2].
Am 02.12.2020 um 18:24 schrieb Florian Stascheck florian.stascheck@gmail.com:
I suggest to allow string keys to also be used in array literals:
$template = ['created_at' =>
time()
, 'is_admin' => 1];
$db_rows = [
['name' => 'Alice', 'email' => 'alice@example.org', ...$template],
['name' => 'Bob', 'email' => 'bob@example.org', ...$template],
];
You can already easily enough do this with
$db_rows = [
['name' => 'Alice', 'email' => 'alice@example.org'] + $template,
['name' => 'Bob', 'email' => 'bob@example.org'] + $template,
];
so I'm not sure if it is really needed.
But then again I'm used to the +-operator for associative arrays and wouldn't expect to be able to use the spread operator instead. Someone learning PHP now might see things differently.
Side-note:
For the ...$template syntax I would assume that later values win (like ['foo' => "bar", 'foo' => "qux"] will result in ['foo' => "qux"]) so the exact equivalent for your example would probably be
$template + ['name' => 'Alice', 'email' => 'alice@example.org'],
but in reality one often wants to be able to override template values, that's why I wrote [ ... ] + $template and your example would be
[...$template, 'name' => 'Alice', 'email' => 'alice@example.org'],
- Chris