array_replace_recursive
Replaces values from later arrays into the first array, descending into nested arrays as it goes.
array_replace_recursive(array $array, array ...$replacements): array- Added in PHP 5.3.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$array | array | The base array whose elements may be replaced. It is not modified. |
$replacementsoptional | array | Any number of arrays applied left to right; later arrays win for duplicate keys. |
Return value
arrayA new array based on the first argument, with matching keys replaced recursively wherever both sides hold an array.
Errors
Throws a TypeError if any argument is not an array.
array_replace_recursive() is the function most people actually mean when they say "deep merge". It applies replacement arrays onto a base array key by key, and whenever both sides hold an array under the same key it descends and repeats the process instead of overwriting.
The exact rule
If both values are arrays, recurse. If either side is a scalar, the replacement's value simply wins — a scalar override replaces an array, and an array override replaces a scalar. Keys present only in the base are left alone; keys present only in a replacement are added.
When to reach for it
Nested configuration is the canonical case: a defaults file with sections for database, cache and logging, and an environment file that overrides two settings without having to restate the rest. It is also right for merging deep option arrays for a library, or applying a partial patch to a nested record.
What trips people up
Lists are merged by index, not concatenated or swapped. Overriding ['a','b','c'] with ['z'] yields ['z','b','c'], because index 0 is replaced and indexes 1 and 2 survive. If your config contains lists of hosts, middleware or allowed values, this quietly leaves stale entries behind. The usual fix is to replace such keys with array_replace() at that level, or to key the list by name instead of by position.
An empty array in a replacement also cannot clear a sub-tree — there is nothing to descend into, so the original survives.
Example
When to use it
- Layer an environment config file over a nested defaults file
- Apply a partial patch to a deeply nested record without restating it
- Merge library option arrays that have several levels of sections
- Combine per-tenant overrides with a shared base configuration
Frequently asked questions
What is the difference between array_replace_recursive and array_merge_recursive?
array_replace_recursive overwrites values at matching keys, while array_merge_recursive collects duplicate string-key values into an array and appends integer-keyed values. For applying overrides on top of defaults you want array_replace_recursive.
Why does array_replace_recursive leave old items in my array?
Because nested lists are merged index by index, not swapped. Overriding a three-item list with a one-item list only replaces index 0, so the other two entries remain — assign that key directly after the merge if you need a clean replacement.
Can I remove a key with array_replace_recursive?
No. Replacement arrays can only set or overwrite keys, and an empty array cannot clear a sub-tree because there is nothing to recurse into. Unset the key on the result afterwards instead.
More examples
Recursive versus flat replace
The recursive version keeps driver and path and updates only ttl. The flat version replaces the whole cache array with the single-key override, losing driver and path — the difference that makes this function the right one for config.
<?php
$base = ['cache' => ['driver' => 'file', 'ttl' => 300, 'path' => 'var/cache']];
$env = ['cache' => ['ttl' => 60]];
echo "recursive:\n";
print_r(array_replace_recursive($base, $env));
echo "flat:\n";
print_r(array_replace($base, $env));The list-merging gotcha and a fix
The first output still contains b.example and c.example, because only index 0 was replaced. Overwriting the key directly after the merge gives the intended single-host list. Any config value that is a positional list needs this treatment.
<?php
$base = ['hosts' => ['a.example', 'b.example', 'c.example']];
$env = ['hosts' => ['only.example']];
print_r(array_replace_recursive($base, $env));
$fixed = array_replace_recursive($base, $env);
$fixed['hosts'] = $env['hosts']; // replace the list wholesale
print_r($fixed);Scalars and arrays replace each other
Recursion only happens when both sides are arrays. Here 'log' becomes the string 'off' and 'flag' becomes an array, because in each case one side is a scalar and the replacement simply wins outright.
<?php
$base = ['log' => ['level' => 'debug'], 'flag' => true];
$over = ['log' => 'off', 'flag' => ['on' => false]];
print_r(array_replace_recursive($base, $over));
Discussion