Signature
array_merge_recursive(array ...$arrays): arrayPurpose
array_merge_recursive() combines any number of arrays into one new array. Unlike array_merge(), it does not let a later string key overwrite an earlier one. When the same string key appears in more than one input, the values are gathered together. If those values are arrays themselves, the function merges them the same way, going as deep as the data goes.
It is useful when you want to accumulate values from several sources, such as collecting tags, error messages or permission lists. It is a poor fit when you want a simple override, which is a common source of surprises.
Signature
Parameters and defaults
...$arrays: zero or more arrays to merge. There are no other parameters and no default values. The arrays are processed from left to right, so earlier arrays come first in the result.
Calling the function with no arguments is allowed and returns an empty array. The manual's changelog notes that this has been possible since PHP 7.4.0.
Return value and failure cases
The function returns a new array. The inputs are not modified. It does not return false on failure. If you pass something that is not an array, such as a string or null, PHP throws a TypeError.
How the merging rules work
- String keys that exist in only one array are copied unchanged.
- String keys that exist in several arrays have their values merged. Scalar values are wrapped into a list and appended together. Array values are merged recursively.
- Numeric keys never collide. Values with numeric keys are appended to the end of the result and renumbered from zero.
Example 1: nested merging
This is the classic case. The key favorite appears in both arrays under color, so its two scalars become a list. The numeric entries are appended and renumbered.
$ar1 = ["color" => ["favorite" => "red"], 5];
$ar2 = [10, "color" => ["favorite" => "green", "blue"]];
$result = array_merge_recursive($ar1, $ar2);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"color":{"favorite":["red","green"],"0":"blue"},"0":5,"1":10}
Notice that blue has a numeric key, so it is appended inside color as element 0, while 5 and 10 become elements 0 and 1 at the top level.
Example 2: contrast with array_merge()
With plain scalar values under the same string key, array_merge() keeps only the last value. array_merge_recursive() keeps both.
$defaults = ["tags" => "php", "level" => 1];
$extra = ["tags" => "arrays", "level" => 2];
echo json_encode(array_merge($defaults, $extra)), "\n";
echo json_encode(array_merge_recursive($defaults, $extra)), "\n";{"tags":"arrays","level":2}
{"tags":["php","arrays"],"level":[1,2]}
The second line shows that level has turned from a number into a list. Code that expects a single integer afterwards will break.
Example 3: numeric keys, no arguments, three inputs
Numeric keys are not preserved, even when they differ. A scalar meeting an array under the same string key is added to that array.
$a = [3 => "a", 7 => "b"];
$b = [3 => "c"];
echo json_encode(array_merge_recursive($a, $b)), "\n";
echo json_encode(array_merge_recursive()), "\n";
echo json_encode(array_merge_recursive(["x" => ["a"]], ["x" => ["b"]], ["x" => "c"])), "\n";["a","b","c"]
[]
{"x":["a","b","c"]}
Edge cases
- Key 3 in both inputs does not collide. Both values are kept and renumbered, so you cannot use numeric IDs as stable keys with this function.
- Numeric strings such as
"5"are treated as integer keys by PHP arrays, so they follow the numeric rule. - Mixed shapes under one key (a scalar in one array, an array in another) produce a list containing both. The result is always an array for a key that appears more than once.
- Result type is unstable. The same key may be a scalar when it appears once and an array when it appears twice. Normalise the result before relying on it.
Common mistakes
- Using it for configuration overrides. If a user setting should replace a default,
array_replace_recursive()is what you want. Witharray_merge_recursive(), a default of"debug" => falseand an override of"debug" => trueyields[false, true], which is truthy and wrong. - Expecting numeric keys to survive. They are renumbered. Use
array_replace()or the+operator when keys matter. - Passing a non-array. A
nullfrom a missing config value triggers aTypeError. Cast or check first. - Assuming a fixed shape. Merged output can change depth and type depending on the inputs, so test with realistic data.
Related functions
array_merge(): shallow merge where later string keys overwrite earlier ones.array_replace_recursive(): recursive merge where later values replace earlier ones.array_replace(): shallow replacement that preserves keys.
Recap
array_merge_recursive() accepts zero or more arrays and returns a new array. Duplicate string keys are combined into lists, nested arrays are merged recursively, and numeric keys are appended and renumbered. It never returns false, but non-array arguments raise a TypeError. Reach for it when you want to collect values, and for array_replace_recursive() when you want to override them.
Tested examples
$ar1 = ["color" => ["favorite" => "red"], 5];
$ar2 = [10, "color" => ["favorite" => "green", "blue"]];
$result = array_merge_recursive($ar1, $ar2);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"color":{"favorite":["red","green"],"0":"blue"},"0":5,"1":10}
$defaults = ["tags" => "php", "level" => 1];
$extra = ["tags" => "arrays", "level" => 2];
echo json_encode(array_merge($defaults, $extra)), "\n";
echo json_encode(array_merge_recursive($defaults, $extra)), "\n";{"tags":"arrays","level":2}
{"tags":["php","arrays"],"level":[1,2]}
$a = [3 => "a", 7 => "b"];
$b = [3 => "c"];
echo json_encode(array_merge_recursive($a, $b)), "\n";
echo json_encode(array_merge_recursive()), "\n";
echo json_encode(array_merge_recursive(["x" => ["a"]], ["x" => ["b"]], ["x" => "c"])), "\n";["a","b","c"]
[]
{"x":["a","b","c"]}