rfc:spread_operator_for_array

Spread Operator in Array Expression

Introduction

PHP has already supported argument unpacking (AKA spread operator) since 5.6. This RFC proposes to bring this feature to array expression.

Proposal

An array pair prefixed by will be expanded in places during array definition. Only arrays and objects who implement Traversable can be expanded.

For example,

$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];

It's possible to do the expansion multiple times, and unlike argument unpacking, can be used anywhere. It's possible to add normal elements before or after the spread operator.

Spread operator works for both array syntax(array()) and short syntax([]).

$arr1 = [1, 2, 3];
$arr2 = [...$arr1]; //[1, 2, 3]
$arr3 = [0, ...$arr1]; //[0, 1, 2, 3]
$arr4 = array(...$arr1, ...$arr2, 111); //[1, 2, 3, 1, 2, 3, 111]

String keys

It's possible to unpack arrays with string keys. When unpacking multiple arrays with same string key, the later value for that key will overwrite the previous one.

For arrays with numeric keys, they will be renumbered with incrementing keys starting from zero. So if unpack multiple arrays with same numeric key, the later value will be appended instead of overwriting the previous one.

It's possible to unpack arrays with mixed string and numeric keys.

$arr1 = ['a' => 1, 'b' => 2, 'c'=> 3];
$arr2 = [11 => 11, 22 => 22, 33 => 33];
$arr3 = [111 => 9, 22 => 8, 'c' => 7];
var_dump([...$arr1, ...$arr2]);
/*
array(6) {
  ["a"]=>
  int(1)
  ["b"]=>
  int(2)
  ["c"]=>
  int(3)
  [0]=>
  int(11)
  [1]=>
  int(22)
  [2]=>
  int(33)
}
*/
var_dump([...$arr1, ...$arr3]);
/*
array(5) { 
  ["a"]=>  
  int(1)   
  ["b"]=>  
  int(2)   
  ["c"]=>  
  int(7)   
  [0]=>    
  int(9)   
  [1]=>    
  int(8)   
}          
*/
var_dump([...$arr2, ...$arr3]);
/*
array(6) {
  [0]=>
  int(11)
  [1]=>
  int(22)
  [2]=>
  int(33)
  [3]=>
  int(9)
  [4]=>
  int(8)
  ["c"]=>
  int(7)
}
*/

Actually there are several ways to handle string keys in PHP now: 1. keep string keys 2. discard string keys, append the values only 3. raise warning / error for string keys

This RFC adopts option 1 for the following reasons. Since the spread operator here is an extension for array defination,and the array defination syntax allows array with string keys, option 3 has been ruled out. Prior to this RFC, array_merge() does the similar job, and it's reasonable to follow the same behaviour in order to not confusing userland developers.

By-reference passing

It's not possible to unpack an array by reference.

$arr1 = [1, 2, 3];
$arr2 = [...&$arr1]; //invalid

However, if elements in the array to be unpacked are stored by reference, they will be stored by reference in the new array as well.

$one = 1;
$arr1 = [&$one, 2, 3];
$arr2 = [0, ...$arr1];
var_dump($arr2);
/*
array(4) {
  [0]=>
  int(0)
  [1]=>
  &int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
}
*/

Backward Incompatible Changes

This change should not break anything.

Proposed PHP Version(s)

next PHP 7.x, likely 7.4

RFC Impact

To Opcache

I'm not sure if this RFC will have any impact on Opcache. I'll check it after I finish the patch.

Proposed Voting Choices

As this is a language change, a 2/3 majority is required.

Patches and Tests

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged into
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature
  4. a link to the language specification section (if any)

References

Links to external references, discussions or RFCs

Rejected Features

Keep this updated with features that were discussed on the mail lists.

rfc/spread_operator_for_array.txt · Last modified: 2018/11/19 08:21 by jhdxr