Array merging: array_merge vs array_replace vs + operator — key collisions
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
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).