0

Array merging: array_merge vs array_replace vs + operator — key collisions

Intermediate5 min read·php-04-012
interview

Concept

PHP has three main ways to combine arrays, each with different key-collision behavior — which one to choose depends entirely on what should happen when both arrays contain the same key.

array_merge($arr1, $arr2, ...) — string keys: later arrays win (overwrite). Integer keys: all values are included with keys reset to sequential integers starting at 0. Commonly used for merging configuration arrays or combining two lists.

array_replace($arr1, $arr2, ...) — string keys: later arrays win (like merge). Integer keys: later arrays also win by key (key 0 from arr2 replaces key 0 from arr1, unlike array_merge which would append). Use when integer keys are semantically meaningful and you want targeted replacement.

+ operator — first array wins for both string and integer keys. Values from later arrays are only used for keys not present in earlier arrays. This is the opposite priority of array_merge for string keys. Useful for providing defaults: $config = $userConfig + $defaults — user settings take precedence, defaults fill in the gaps.

array_merge_recursive: when string keys collide, values are merged into a nested array rather than overwriting. Rarely what you want for simple config merging but useful for building grouped structures.

Code Example

php
<?php
declare(strict_types=1);

$defaults = ['color' => 'blue', 'size' => 'medium', 'weight' => 100];
$overrides = ['color' => 'red', 'material' => 'steel'];

// array_merge — later wins, integer keys reset
$merged = array_merge($defaults, $overrides);
// ['color' => 'red', 'size' => 'medium', 'weight' => 100, 'material' => 'steel']

// + operator — first wins (defaults pattern)
$withDefaults = $overrides + $defaults;
// ['color' => 'red', 'material' => 'steel', 'size' => 'medium', 'weight' => 100]

// Integer key behavior — critical difference
$a = [0 => 'a', 1 => 'b'];
$b = [0 => 'x', 1 => 'y'];

print_r(array_merge($a, $b));
// [0 => 'a', 1 => 'b', 2 => 'x', 3 => 'y'] — all 4, keys reset

print_r($a + $b);
// [0 => 'a', 1 => 'b'] — $a wins, $b keys 0 and 1 are ignored

// array_replace — integer keys are replaced, not appended
print_r(array_replace($a, $b));
// [0 => 'x', 1 => 'y'] — $b's values replace $a's at same integer keys

// Config defaults pattern — the idiomatic PHP way
function getConfig(array $userConfig): array
{
    $defaults = [
        'debug' => false,
        'cache_ttl' => 3600,
        'driver' => 'file',
    ];
    return $userConfig + $defaults; // user settings override defaults
}

$config = getConfig(['debug' => true, 'driver' => 'redis']);
// ['debug' => true, 'driver' => 'redis', 'cache_ttl' => 3600]

// Merging multiple arrays (spread operator alternative)
$tags1 = ['php', 'laravel'];
$tags2 = ['backend', 'api'];
$tags3 = ['testing'];
$allTags = array_merge($tags1, $tags2, $tags3);
// OR: [...$tags1, ...$tags2, ...$tags3]  — spread operator, same result

// array_merge_recursive — values become arrays on collision
$a = ['key' => 'value1', 'other' => 'x'];
$b = ['key' => 'value2', 'new' => 'y'];
print_r(array_merge_recursive($a, $b));
// ['key' => ['value1', 'value2'], 'other' => 'x', 'new' => 'y']

Interview Q&A

Q: What is the difference between array_merge and the + operator when combining arrays with duplicate string keys?

Both handle string key collisions differently in terms of priority: array_merge gives precedence to the later array (right operand wins), while + gives precedence to the earlier array (left operand wins). For integer keys the difference is more dramatic: array_merge renumbers all integer keys sequentially, concatenating all values; + keeps the left array's integer keys and ignores any conflicting keys from the right. The + operator is ideal for the "user config over defaults" pattern because you put the user config first and it naturally wins.


Q: When would you use array_replace instead of array_merge?

array_replace is the right choice when integer keys are semantically meaningful and you want targeted replacement by key rather than appending. For example, if you have a zero-indexed array representing positional data (like database row results indexed by position), array_replace lets you overwrite specific positions while array_merge would just concatenate. In practice, array_replace is rarely used — most array merging scenarios either deal with string keys (where merge and replace behave the same) or sequential lists (where merge's appending behavior is desired).