Arrays7 min readExamples run on PHP 8.5.10

array_replace_recursive()

Learn how array_replace_recursive() overlays nested arrays key by key in PHP 8.4, with its signature, return value, practical examples, edge cases and pitfalls.

Signature

array_replace_recursive(array $array, array ...$replacements): array
Available since PHP 5.3.07.48.08.18.28.38.48.5All versions →

Purpose

array_replace_recursive() lays one or more arrays on top of a base array and returns the combined result. Matching keys take their value from the later array. Keys that exist only in the later array are added. Keys that exist only in the base array stay as they were. The "recursive" part means that when both sides hold an array under the same key, PHP does not swap the whole inner array. It repeats the same process inside it.

The typical use is layered configuration: a full set of defaults, with a small override array that changes only a few deep settings.

Signature

Parameters and defaults

  • $array: the base array. Its values are the ones that get replaced.
  • ...$replacements: zero or more arrays applied in order from left to right. When two replacement arrays touch the same key, the later one wins.

There are no default values. If you pass only the base array, you get back an array with the same contents.

Return value and failure cases

The function returns a new array. The arrays you passed in are not modified, because arrays are passed by value. Every argument must be an array. Passing something else, such as null or a string, throws a TypeError, so check optional configuration before the call.

The merge rule

For each key in a replacement array:

  1. If the base value and the replacement value are both arrays, the function recurses into them.
  2. Otherwise the replacement value wins. A scalar can replace an array, and an array can replace a scalar.
  3. If the key is missing in the base, it is created.

Example 1: overriding nested configuration

Only the port changes inside db. The host survives because the inner arrays are merged rather than swapped.

Example
<?php
$defaults = [
    'db' => ['host' => 'localhost', 'port' => 3306],
    'debug' => false,
];
$overrides = [
    'db' => ['port' => 3307],
    'debug' => true,
];
echo json_encode(array_replace_recursive($defaults, $overrides), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"db":{"host":"localhost","port":3307},"debug":true}

Example 2: comparison with array_replace()

Both functions replace by key. Plain array_replace() swaps the entire inner list, while the recursive version replaces only index 0 and keeps the remaining elements.

Example
<?php
$base = ['berries' => ['blackberry', 'raspberry', 'cranberry']];
$new = ['berries' => ['blueberry']];
echo json_encode(array_replace_recursive($base, $new), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
echo json_encode(array_replace($base, $new), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"berries":["blueberry","raspberry","cranberry"]}
{"berries":["blueberry"]}

Example 3: several replacements and type changes

The first replacement turns a into a string and b into an array. The second replacement then puts an array back over the string in a. Under c, an empty replacement array has nothing to contribute, so the original list is kept.

Example
<?php
$base = ['a' => ['x' => 1, 'y' => 2], 'b' => 'text', 'c' => [1, 2]];
$r1 = ['a' => 'flat', 'b' => ['now' => 'array']];
$r2 = ['a' => ['z' => 3], 'c' => []];
echo json_encode(array_replace_recursive($base, $r1, $r2), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"a":{"z":3},"b":{"now":"array"},"c":[1,2]}

Edge cases

  • Integer keys are matched, not appended. The list ['a', 'b'] is treated as keys 0 and 1. A replacement list ['z'] overwrites key 0 and leaves key 1 alone. Lists are never concatenated.
  • Numeric string keys such as "5" become integer keys, as they do in any PHP array, so they match integer keys.
  • An empty replacement array inside a nested position changes nothing. You cannot use it to clear an inner array. To clear a value, replace it with a non-array value such as null, and then handle that value yourself.
  • Order matters. array_replace_recursive($a, $b) and array_replace_recursive($b, $a) give different results whenever the arrays share keys.
  • Mixed types are allowed. Whenever one side is not an array, the replacement value simply wins, whatever its type.

Common mistakes

  • Expecting list concatenation. If you want to append items, this is the wrong tool. array_merge_recursive() combines differently, and it renumbers integer keys and gathers duplicate string keys into arrays.
  • Expecting renumbering. Integer keys keep their identity, so sparse keys stay sparse.
  • Passing null as an override. A missing configuration source must become [] before the call, for example with $extra ?? [].
  • Assuming arrays can be removed. The function adds and overwrites keys. It never deletes them.
  • Choosing it when a shallow replacement is intended. If the whole inner array should be swapped, use array_replace() or the + operator instead.
  • array_replace() replaces by key at the top level only.
  • array_merge_recursive() merges recursively, with different rules for keys.
  • array_merge() merges at the top level, renumbering integer keys.

Recap

array_replace_recursive() overlays arrays from left to right, key by key, descending wherever both values are arrays. Anything else is decided by the later value. It returns a new array, never removes keys, treats integer keys by position, and throws a TypeError for non-array arguments.

Tested examples

Overriding nested configuration defaults
<?php
$defaults = [
    'db' => ['host' => 'localhost', 'port' => 3306],
    'debug' => false,
];
$overrides = [
    'db' => ['port' => 3307],
    'debug' => true,
];
echo json_encode(array_replace_recursive($defaults, $overrides), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"db":{"host":"localhost","port":3307},"debug":true}
Comparison with array_replace()
<?php
$base = ['berries' => ['blackberry', 'raspberry', 'cranberry']];
$new = ['berries' => ['blueberry']];
echo json_encode(array_replace_recursive($base, $new), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
echo json_encode(array_replace($base, $new), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"berries":["blueberry","raspberry","cranberry"]}
{"berries":["blueberry"]}
Several replacements and type changes
<?php
$base = ['a' => ['x' => 1, 'y' => 2], 'b' => 'text', 'c' => [1, 2]];
$r1 = ['a' => 'flat', 'b' => ['now' => 'array']];
$r2 = ['a' => ['z' => 3], 'c' => []];
echo json_encode(array_replace_recursive($base, $r1, $r2), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"a":{"z":3},"b":{"now":"array"},"c":[1,2]}