Слияние массивов в PHP: полное руководство
Объединение массивов в PHP: способы и особенности
Слияние массивов - одна из частых операций при работе с данными. В PHP существует несколько подходов, каждый из которых подходит для определённых сценариев. В этом материале рассмотрены основные методы, их преимущества и потенциальные ошибки.
Наиболее универсальное решение: array_merge
Функция array_merge объединяет два или более массива, перезаписывая значения с одинаковыми строковыми ключами (последний аргумент имеет приоритет) и переиндексируя числовые ключи.
$arr1 = ['a' => 1, 'b' => 2];
$arr2 = ['b' => 3, 'c' => 4];
$result = array_merge($arr1, $arr2);
// $result = ['a' => 1, 'b' => 3, 'c' => 4]
Числовые ключи будут перенумерованы с нуля, поэтому предыдущие индексы теряются.
Типичная ошибка: при слиянии массивов с числовыми ключами теряются исходные индексы, что может привести к непредсказуемому порядку. Если требуется сохранить числовые ключи, используйте оператор +.
Как объединить массивы без перезаписи существующих ключей?
Оператор + добавляет элементы второго массива только тогда, когда ключ отсутствует в первом. При этом числовые ключи считаются строковыми (не переиндексируются).
$arr1 = [0 => 'apple', 1 => 'banana'];
$arr2 = [0 => 'cherry', 2 => 'date'];
$result = $arr1 + $arr2;
// $result = [0 => 'apple', 1 => 'banana', 2 => 'date']
Проблема: при совпадении строковых ключей значение из первого массива остаётся, что может быть неочевидно.
Как рекурсивно объединить вложенные массивы?
array_merge_recursive работает как array_merge, но для одинаковых строковых ключей формирует массив значений, а не перезаписывает.
$arr1 = ['color' => ['r' => 255]];
$arr2 = ['color' => ['g' => 128]];
$result = array_merge_recursive($arr1, $arr2);
// $result = ['color' => ['r' => 255, 'g' => 128]]
Ошибка: если на одном уровне встречаются строковый ключ и числовой, результат может быть неожиданным.
Как объединить массивы с использованием spread-оператора?
Начиная с PHP 7.4 (для ассоциативных массивов с PHP 8.1) можно использовать ... внутри литерала массива. Работает аналогично array_merge.
$arr1 = ['x' => 10];
$arr2 = ['y' => 20];
$result = [...$arr1, ...$arr2];
// $result = ['x' => 10, 'y' => 20]
Ограничение: spread не поддерживает многомерное рекурсивное слияние и может быть медленнее на больших массивах.
Как заменить значения при совпадении ключей?
array_replace замещает значения первого массива значениями второго при совпадении ключей (как строковых, так и числовых).
$arr1 = ['a' => 1, 'b' => 2];
$arr2 = ['a' => 3, 'c' => 4];
$result = array_replace($arr1, $arr2);
// $result = ['a' => 3, 'b' => 2, 'c' => 4]
Различие с array_merge: числовые ключи не переиндексируются, что может быть неудобно при работе с пронумерованными списками.
Как добавить элементы в конец массива?
Для простого добавления одного или нескольких элементов используется array_push.
$fruits = ['apple'];
array_push($fruits, 'banana', 'cherry');
// $fruits = ['apple', 'banana', 'cherry']
Для слияния нескольких массивов array_push не подходит - он добавит второй массив как вложенный.
Ошибка: передача массива вторым аргументом в array_push поместит его целиком, а не раскроет элементы.
Как вручную объединить массивы через цикл?
Для полного контроля над процессом можно использовать foreach.
$merged = [];
foreach ([$arr1, $arr2] as $arr) {
foreach ($arr as $key => $value) {
$merged[$key] = $value; // перезапись или добавление
}
}
Недостаток: код становится громоздким, легко допустить ошибки при обработке числовых ключей.
Расширенные примеры объединения массивов
Слияние нескольких массивов с разными типами ключей
$arr1 = ['name' => 'Alice', 0 => 'admin'];
$arr2 = [1 => 'editor', 'name' => 'Bob'];
$arr3 = ['role' => 'user'];
// array_merge переиндексирует числовые ключи
$merged = array_merge($arr1, $arr2, $arr3);
print_r($merged);
Array
(
[name] => Bob # перезапись строкового ключа
[0] => admin
[1] => editor
[role] => user
)
Числовые ключи 0 и 1 из первого массива смешались с ключами второго, порядок может сбить с толку.
Использование оператора + для сохранения оригинальных индексов
$arr1 = [0 => 'red', 1 => 'green']; // индексы 0 и 1
$arr2 = [0 => 'blue', 2 => 'yellow'];
$result = $arr1 + $arr2;
print_r($result);
Array
(
[0] => red
[1] => green
[2] => yellow
)
Первое значение при совпадении числовых ключей не заменяется.
Рекурсивное слияние с array_merge_recursive на трёх уровнях вложенности
$deep1 = ['config' => ['db' => ['host' => 'localhost']]];
$deep2 = ['config' => ['db' => ['port' => 3306, 'user' => 'root']]];
$deep3 = ['config' => ['app' => ['debug' => true]]];
$merged = array_merge_recursive($deep1, $deep2, $deep3);
print_r($merged);
Array
(
[config] => Array
(
[db] => Array
(
[host] => localhost
[port] => 3306
[user] => root
)
[app] => Array
(
[debug] => 1
)
)
)
Ключи объединились рекурсивно, значения не перезаписываются.
Слияние с заменой через array_replace при числовых ключах
$base = [0 => 'one', 1 => 'two', 2 => 'three'];
$override = [1 => 'TWO', 3 => 'four'];
$result = array_replace($base, $override);
print_r($result);
Array
(
[0] => one
[1] => TWO
[2] => three
[3] => four
)
Числовые ключи не переиндексируются, индекс 1 заменён, добавлен новый ключ 3.
Spread-оператор с ассоциативными и числовыми ключами (PHP 8.1+)
$colors = ['red', 'green'];
$more = ['blue', 'yellow'];
$combined = [...$colors, ...$more];
print_r($combined);
Array
(
[0] => red
[1] => green
[2] => blue
[3] => yellow
)
Для ассоциативных массивов spread ведёт себя как array_merge.
Комбинация array_merge и array_map для обработки перед слиянием
$arrays = [
['a' => 1, 'b' => 2],
['a' => 3, 'c' => 4],
['b' => 5, 'd' => 6]
];
$processed = array_map(function($arr) {
return array_filter($arr, fn($v) => $v > 2);
}, $arrays);
$flatten = array_merge(...$processed);
print_r($flatten);
Array
(
[a] => 3
[c] => 4
[b] => 5
[d] => 6
)
Сначала отфильтрованы значения, затем массивы слиты в один.
Объединение массивов с помощью array_push в цикле (не рекомендуется)
$result = ['x' => 1];
$extra = ['y' => 2, 'z' => 3];
foreach ($extra as $key => $value) {
$result[$key] = $value;
}
print_r($result);
Array
(
[x] => 1
[y] => 2
[z] => 3
)
Ручной цикл даёт полный контроль, но менее выразителен.