array_merge($a, $b) возвращает новый массив, где за элементами $a идут элементы $b. Числовые ключи перенумеровываются с 0; когда в обоих массивах есть один и тот же строковый ключ, побеждает значение из более позднего массива. Передавать можно сколько угодно массивов.
array_merge() не меняет свои аргументы. Она возвращает объединённый массив, поэтому присваивайте результат: $all = array_merge($all, $more);.
Числовые ключи перенумеровываются
array_merge() воспринимает целочисленные ключи как позиции, а не как имена. Каждый элемент с целочисленным ключом добавляется в конец и получает новый ключ начиная с 0, даже если массивы использовали одинаковые номера или в них были пропуски. Для списков это то, что нужно, а когда числа это ID, это сюрприз.
Строковые ключи, похожие на целые числа ('101'), хранятся как целые, поэтому тоже перенумеровываются. Ключи вроде 'id101' остаются как есть.
array_merge и оператор +
Оператор + (объединение массивов) тоже соединяет массивы, но по противоположному правилу: для любого ключа, который уже есть в левом массиве, побеждает левое значение, а правое отбрасывается. Он никогда не перенумеровывает. Поэтому + естественный способ подставить значения по умолчанию, а array_merge() естественный способ их переопределить.
array_merge($a, $b) | $a + $b | |
|---|---|---|
| Одинаковый строковый ключ | значение из $b | значение из $a |
| Целочисленные ключи | перенумерованы, все значения сохранены | сохранены, $b проигрывает при совпадении |
| Типичное применение | объединение списков, переопределение настроек | подстановка значений по умолчанию, сохранение ID |
Последний пример в блоке это классическая ловушка +: ['a', 'b'] + ['x', 'y', 'z'] даёт a, b, z, потому что ключи 0 и 1 уже есть слева.
Распаковка: [...b]
Оператор распаковки разворачивает массивы внутри литерала массива. Он ведёт себя как array_merge(): целочисленные ключи перенумеровываются, а начиная с PHP 8.1 допускаются строковые ключи, и побеждает более поздний. Он хорошо читается, когда массивы смешиваются с отдельными значениями.
Чтобы дописать массив к существующему на месте, смотрите array_push() с оператором распаковки.
Объединение массива массивов
Когда объединяемые массивы сами лежат в списке, распакуйте этот список в array_merge(). Это ещё и быстрый способ объединять в цикле: соберите части, потом объедините один раз.
Запись $all = array_merge($all, $batch); внутри цикла работает, но на каждом проходе копирует весь растущий массив, и на тысячах элементов это становится медленно.
array_merge_recursive и array_replace
array_merge_recursive() объединяет и вложенные массивы, но для одинакового строкового ключа с простыми значениями не перезаписывает их, а собирает оба значения в новый массив. Для настроек это редко то, что нужно. Там обычно правильный инструмент array_replace_recursive(): она перезаписывает значения на всех уровнях и сохраняет ключи.
Прочитайте три строки JSON сверху вниз: array_merge() заменила весь массив db и потеряла host, array_merge_recursive() превратила port и debug в списки из двух элементов, а array_replace_recursive() дала ту конфигурацию, которую вы имели в виду.
Частая ошибка: слияние ничего не удаляет
array_merge() сохраняет повторяющиеся значения, которые лежат под разными ключами. Объединив два списка тегов, вы получите каждый общий тег дважды. Пропустите результат через array_unique(), а затем через array_values(), чтобы перенумеровать его.
Удаление дубликатов из строк и вложенных массивов описано на странице про array_unique.
Часто задаваемые вопросы
Чем array_merge отличается от + в PHP?
Для одинаковых строковых ключей array_merge($a, $b) оставляет значение из $b, а $a + $b оставляет значение из $a. Для числовых ключей array_merge() добавляет всё в конец и перенумеровывает, а + сохраняет числовые ключи и отбрасывает элементы $b, ключ которых уже есть в $a.
Как объединить массивы и сохранить числовые ключи?
Используйте $a + $b, если должен побеждать левый массив, или array_replace($a, $b), если правый. array_merge() всегда перенумеровывает числовые ключи с 0.
Как объединить массив массивов в PHP?
Распакуйте внешний массив в array_merge(): $all = array_merge(...$lists);. Для пустого списка функция вернёт []. Сначала соберите массивы в цикле, а объединяйте один раз в конце; вызов array_merge() внутри цикла каждый раз копирует растущий результат.
Можно ли использовать оператор распаковки со строковыми ключами в PHP?
Да, начиная с PHP 8.1. [...$a, ...$b] тогда ведёт себя как array_merge($a, $b): числовые ключи перенумеровываются, а более поздний строковый ключ перезаписывает более ранний.