Arrays7 min readExamples run on PHP 8.5.10

array_merge_recursive()

Learn how array_merge_recursive() combines arrays in PHP 8.4, why duplicate string keys become lists, and when array_replace_recursive() is the better choice.

Signature

array_merge_recursive(array ...$arrays): array
Available since PHP 4.0.17.48.08.18.28.38.48.5All versions →

Purpose

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

  1. String keys that exist in only one array are copied unchanged.
  2. 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.
  3. 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.

Example
<?php
$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";
Output
{"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.

Example
<?php
$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";
Output
{"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.

Example
<?php
$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";
Output
["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. With array_merge_recursive(), a default of "debug" => false and an override of "debug" => true yields [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 null from a missing config value triggers a TypeError. Cast or check first.
  • Assuming a fixed shape. Merged output can change depth and type depending on the inputs, so test with realistic data.
  • 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

Nested merging with string and numeric keys
<?php
$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";
Output
{"color":{"favorite":["red","green"],"0":"blue"},"0":5,"1":10}
Comparing array_merge() with array_merge_recursive()
<?php
$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";
Output
{"tags":"arrays","level":2}
{"tags":["php","arrays"],"level":[1,2]}
Numeric keys, no arguments and three inputs
<?php
$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";
Output
["a","b","c"]
[]
{"x":["a","b","c"]}