Array merge recursive: примеры (PHP)
array_merge_recursive(array ...$arrays): arrayОсновные сведения о array_merge_recursive
Функция array_merge_recursive в PHP выполняет рекурсивное слияние нескольких массивов. Она используется в случаях, когда требуется объединить массивы, содержащие одинаковые строковые ключи, без потери данных. В отличие от array_merge, при обнаружении одинаковых строковых ключей значения объединяются в массив, а не перезаписываются.
Синтаксис: array_merge_recursive(array ...$arrays): array
Функция принимает переменное количество аргументов:
- ...$arrays – один или более массивов для рекурсивного слияния. Минимум один массив должен быть передан.
Базовые примеры использования
$arr1 = ['color' => 'red', 'size' => 'M'];
$arr2 = ['color' => 'blue', 'weight' => 100];
$result = array_merge_recursive($arr1, $arr2);
print_r($result);Array
(
[color] => Array
(
[0] => red
[1] => blue
)
[size] => M
[weight] => 100
)
$arr1 = ['data' => ['id' => 1, 'values' => [1, 2]]];
$arr2 = ['data' => ['id' => 2, 'values' => [3, 4]]];
$result = array_merge_recursive($arr1, $arr2);
print_r($result);Array
(
[data] => Array
(
[id] => Array
(
[0] => 1
[1] => 2
)
[values] => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
)
)
$arr1 = [1 => 'a', 2 => 'b'];
$arr2 = [3 => 'c', 4 => 'd'];
$result = array_merge_recursive($arr1, $arr2);
print_r($result);Array
(
[0] => a
[1] => b
[2] => c
[3] => d
)
Похожие функции в PHP
Функция array_merge выполняет нерекурсивное слияние массивов. При совпадении строковых ключей значение из последнего массива перезаписывает предыдущее. Числовые ключи переиндексируются.
Функция array_replace_recursive заменяет элементы массива элементами других переданных массивов рекурсивно. При совпадении ключей значение из последнего массива заменяет предыдущее, в отличие от array_merge_recursive, которая создает массив значений.
array_merge_recursive применяется, когда нужно сохранить все значения из всех массивов по одинаковым ключам. array_merge используется для простого объединения с приоритетом последних значений. array_replace_recursive подходит для рекурсивного замещения значений.
Распространенные ошибки
Частой ошибкой является непонимание того, что функция всегда создает массив для одинаковых строковых ключей, даже если значения скалярные.
$arr1 = ['id' => 1];
$arr2 = ['id' => 2];
$result = array_merge_recursive($arr1, $arr2);
var_dump($result['id']);array(2) {
[0]=> int(1)
[1]=> int(2)
}При слиянии внутренних массивов с числовыми ключами происходит их переиндексация.
$arr1 = ['items' => [10 => 'apple']];
$arr2 = ['items' => [20 => 'banana']];
$result = array_merge_recursive($arr1, $arr2);
print_r($result);Array
(
[items] => Array
(
[0] => apple
[1] => banana
)
)
Если в одинаковых ключах содержатся разные типы данных (массив и скаляр), результат может быть неочевидным.
$arr1 = ['data' => 'string'];
$arr2 = ['data' => ['array']];
$result = array_merge_recursive($arr1, $arr2);
print_r($result);Array
(
[data] => Array
(
[0] => string
[1] => array
)
)
Изменения в последних версиях PHP
В PHP 8.0 функция array_merge_recursive не претерпела значительных изменений в поведении. Однако, как и многие другие функции, она стала строже относиться к типам передаваемых аргументов. Передача не массива теперь вызывает TypeError.
array_merge_recursive([], 'not_array');TypeError: array_merge_recursive(): Argument #2 must be of type array, string given
До PHP 7.4 функция корректно обрабатывала только массивы и скаляры. Сейчас она также работает с объектами, реализующими интерфейс Traversable, но они преобразуются в массивы.
Расширенные примеры применения
$arr1 = ['a' => 1, 'b' => 2];
$arr2 = ['a' => 3, 'c' => 4];
$arr3 = ['a' => 5, 'd' => 6];
$result = array_merge_recursive($arr1, $arr2, $arr3);
print_r($result);Array
(
[a] => Array
(
[0] => 1
[1] => 3
[2] => 5
)
[b] => 2
[c] => 4
[d] => 6
)
$arr1 = [
'database' => [
'host' => 'localhost',
'port' => 3306,
'options' => ['charset' => 'utf8']
]
];
$arr2 = [
'database' => [
'host' => '127.0.0.1',
'options' => ['collation' => 'utf8_general_ci']
],
'debug' => true
];
$result = array_merge_recursive($arr1, $arr2);
print_r($result);Array
(
[database] => Array
(
[host] => Array
(
[0] => localhost
[1] => 127.0.0.1
)
[port] => 3306
[options] => Array
(
[charset] => utf8
[collation] => utf8_general_ci
)
)
[debug] => 1
)
$arr1 = [0 => 'zero', 'key' => 'value1', 2 => 'two'];
$arr2 = [0 => 'ZERO', 'key' => 'value2', 3 => 'three'];
$result = array_merge_recursive($arr1, $arr2);
print_r($result);Array
(
[0] => zero
[key] => Array
(
[0] => value1
[1] => value2
)
[1] => two
[2] => ZERO
[3] => three
)
$obj1 = (object)['prop' => 'val1'];
$obj2 = (object)['prop' => 'val2'];
$arr1 = ['object' => $obj1];
$arr2 = ['object' => $obj2];
$result = array_merge_recursive($arr1, $arr2);
print_r($result);Array
(
[object] => Array
(
[0] => stdClass Object
(
[prop] => val1
)
[1] => stdClass Object
(
[prop] => val2
)
)
)
Аналоги в других языках программирования
В JavaScript отсутствует встроенная функция для рекурсивного слияния массивов с сохранением всех значений. Пример реализации:
function mergeRecursive(target, source) {
for (let key in source) {
if (source[key] instanceof Object && key in target) {
mergeRecursive(target[key], source[key]);
} else if (Array.isArray(target[key]) && Array.isArray(source[key])) {
target[key] = target[key].concat(source[key]);
} else if (target.hasOwnProperty(key)) {
target[key] = [target[key], source[key]];
} else {
target[key] = source[key];
}
}
return target;
}
let obj1 = { color: 'red', size: 'M' };
let obj2 = { color: 'blue', weight: 100 };
console.log(mergeRecursive(obj1, obj2));{ color: [ 'red', 'blue' ], size: 'M', weight: 100 }В Python можно использовать метод update с дополнительной логикой или библиотеку deepmerge.
def merge_recursive(dict1, dict2):
for key, value in dict2.items():
if key in dict1 and isinstance(dict1[key], dict) and isinstance(value, dict):
merge_recursive(dict1[key], value)
elif key in dict1:
dict1[key] = [dict1[key], value] if not isinstance(dict1[key], list) else dict1[key] + [value]
else:
dict1[key] = value
return dict1
dict1 = {'color': 'red', 'size': 'M'}
dict2 = {'color': 'blue', 'weight': 100}
print(merge_recursive(dict1, dict2)){'color': ['red', 'blue'], 'size': 'M', 'weight': 100}В MySQL для работы с JSON существует функция JSON_MERGE_PATCH (замена) и JSON_MERGE_PRESERVE (сохранение всех значений).
SELECT JSON_MERGE_PRESERVE('{"color": "red"}', '{"color": "blue"}') AS result;result: {"color": ["red", "blue"]}