I learned something today

I learned a new thing today while reading through someone else’s code (nikic/FastRoute if you’re interested). I was reading through a function and noticed them using a varient of the + operator with 2 arrays:

<?php

// ...

function cachedDispatcher(callable $routeDefinitionCallback, array $options = []): Dispatcher
    {
        $options += [
            'routeParser' => RouteParser\Std::class,
            'dataGenerator' => DataGenerator\MarkBased::class,
            'dispatcher' => Dispatcher\MarkBased::class,
            'routeCollector' => RouteCollector::class,
            'cacheDisabled' => false,
            'cacheDriver' => FileCache::class,
        ];

// ...

This led me to review the documentation on array operators:

The + operator returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored.

Note, that this is different from array_merge() which, per the documentation:

If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.

Values in the input arrays with numeric keys will be renumbered with incrementing keys starting from zero in the result array.

Example code

I threw together some example code to get my head wrapped around what this all meant.

Code

<?php

$a = [
    1 => 'a_one',
    2 => 'a_two',
    5 => 'a_five',
    10 => 'number_shared',
    'a' => 'a_a',
    'b' => 'a_b',
    'shared' => 'shared',
    'a_unique' => true
];


$b = [
    'shared' => 'shared',
    1 => 'b_one',
    2 => 'b_two',
    5 => 'b_five',
    10 => 'number_shared',
    'a' => 'b_a',
    'b' => 'b_b',
    'b_unique' => true
];


echo "Plus operator:\n";
var_export($a + $b);

echo "\n\narray_merge():\n";
var_export(array_merge($a, $b));

Output

Plus operator:
array (
  1 => 'a_one',
  2 => 'a_two',
  5 => 'a_five',
  10 => 'number_shared',
  'a' => 'a_a',
  'b' => 'a_b',
  'shared' => 'shared',
  'a_unique' => true,
  'b_unique' => true,
)

array_merge():
array (
  0 => 'a_one',
  1 => 'a_two',
  2 => 'a_five',
  3 => 'number_shared',
  'a' => 'b_a',
  'b' => 'b_b',
  'shared' => 'shared',
  'a_unique' => true,
  4 => 'b_one',
  5 => 'b_two',
  6 => 'b_five',
  7 => 'number_shared',
  'b_unique' => true,
)

The upshot

Facet$left + $rightarray_merge($left, $right)
Matching key overrideLeft overrides rightRight overrides left
Numeric keys are magic?No, all keys are the sameYes, they will all be renumbered from 0, and right appended to left.
Key orderLeft most occurrence defines orderLeft most occurrence defines order

-j42h