PHPのarray_merge関数 — 複数配列をマージする基本と落とし穴

基本文法・構文ガイド
  • カテゴリ: PHP
  • 名前空間 / FQCN / コマンド: array_merge(array ...$arrays): array
  • 関連: array_merge_recursive / array_replace / +演算子 / array_combine / array_push
  • 変更履歴: PHP 7.4.0 以降、引数なしでの呼び出しが可能(空配列を返す)。PHP 8.1 以降、引数に null を渡すと非推奨警告

要点(TL;DR)

  • 複数の配列を1つにまとめる標準関数。文字列キーは後の配列が上書き数値キーは0から振り直される
  • 最低限の使い方:$merged = array_merge($array1, $array2);
  • 罠:
    • 数値キーを保持したいなら array_merge ではなく + 演算子array_replace を使う
    • ネストした配列は再帰的にマージされない(後の配列で丸ごと上書き)
    • PHP 8.1 以降、null を渡すと Deprecated 警告が出る

概要

array_merge は、渡した複数の配列を左から右へ順番に結合し、新しい配列を1つ返す標準関数です。設定値のデフォルトとユーザー指定値の統合、複数ソースから集めた配列の結合、タグやIDリストの合算など、PHP開発で最も使用頻度の高い配列操作の1つです。Laravelの Collection::merge()関連記事)とは挙動が似ていますが別物なので、ネイティブ配列を扱う場面では本関数を使います。

構文 / シグネチャ

array array_merge(array ...$arrays)
  • 引数$arrays(可変長・array) — マージ対象の配列を任意の数だけ渡す。PHP 7.4.0以降は0個でも呼び出し可能(空配列を返す)。左の配列から順に処理され、後に渡した配列が優先される。
  • 戻り値array — マージ結果の新しい配列。引数がなければ空配列 []
  • 例外/副作用
    • TypeError: 配列でない値(文字列・null・オブジェクトなど)を渡した場合
    • PHP 8.1以降: null を渡すと Deprecated: array_merge(): Passing null to parameter #N ($arrays) of type array is deprecated が発生(PHP 9で TypeError になる予定)
    • 元の配列は変更されない(新しい配列を返す純粋関数)

使用例

最小例:連想配列のデフォルト値をユーザー指定値で上書き

<?php
$defaults = ['timeout' => 30, 'retries' => 3, 'debug' => false];
$options  = ['retries' => 5, 'debug' => true];

$config = array_merge($defaults, $options);
// ['timeout' => 30, 'retries' => 5, 'debug' => true]
// 同じキー(retries, debug)は後に渡した $options が優先される

数値キーは0から振り直される

<?php
$array1 = [0 => 'a', 5 => 'b'];
$array2 = [0 => 'c', 1 => 'd'];

$result = array_merge($array1, $array2);
// [0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd']
// 元のキー(0, 5, 0, 1)は無視され、連番で振り直される

実務例:複数配列のタグを1つに合算して重複除去

<?php
$tagsFromA = ['php', 'laravel', 'array'];
$tagsFromB = ['laravel', 'eloquent'];

$allTags = array_merge($tagsFromA, $tagsFromB);
// ['php', 'laravel', 'array', 'laravel', 'eloquent']

$uniqueTags = array_values(array_unique($allTags));
// ['php', 'laravel', 'array', 'eloquent']

可変個の配列を一括結合(スプレッド展開)

<?php
$chunks = [
    ['a', 'b'],
    ['c'],
    ['d', 'e', 'f'],
];

// 配列の配列は ... で展開してから渡す
$flat = array_merge(...$chunks);
// ['a', 'b', 'c', 'd', 'e', 'f']

array_merge+ 演算子の違い

<?php
$a = [0 => 'a', 'key' => 'x'];
$b = [0 => 'b', 'key' => 'y'];

// array_merge: 数値キーは再採番、文字列キーは「後」が勝つ
array_merge($a, $b);
// [0 => 'a', 1 => 'b', 'key' => 'y']

// + 演算子: 数値・文字列とも「前(左)」が勝ち、キーは保持される
$a + $b;
// [0 => 'a', 'key' => 'x']

PHP 8.1以降のnull非推奨警告を回避する

<?php
function mergeOptions(array $base, ?array $overrides): array
{
    // $overrides が null の可能性がある場合は ?? [] でフォールバック
    return array_merge($base, $overrides ?? []);
}

mergeOptions(['a' => 1], null); // ['a' => 1](Deprecated警告なし)

よくある落とし穴・注意

  • 数値キーが再採番される:IDをキーにした配列を結合すると、キーの対応関係が崩れる。キーを保持したい場合は + 演算子または array_replace を使う。
  • 文字列キーは後勝ちarray_merge($defaults, $user) の順で渡さないと、ユーザー指定値がデフォルト値に上書きされてしまう。
  • ネスト配列は再帰しない['opts' => ['a' => 1]]['opts' => ['b' => 2]] をマージすると、内側の配列ごと後の値で置き換わる(['opts' => ['b' => 2]])。深い階層を統合したいなら array_merge_recursivearray_replace_recursive を検討。
  • ループ内での多用はO(n²)で遅いforeach の中で毎回 $result = array_merge($result, $chunk); すると要素数に応じて遅くなる。配列をまとめてから最後に1回 array_merge(...$chunks) するか、$result[] = ...array_push を使う。
  • null引数はPHP 8.1以降非推奨:nullable な変数を渡す可能性がある場合は ?? [] で空配列にフォールバックする。

代替・関連APIとの比較

  • array_merge_recursive:同じキーの値が両方とも配列なら再帰的に統合する。文字列キーの値が配列でない場合は配列化されてしまう点に注意。
  • array_replacearray_merge と似ているが、数値キーも再採番せず保持したまま置き換える。
  • + 演算子:キーを保持し、重複キーは先(左)の配列の値を優先array_merge とは優先順位・キー再採番の両方が逆になる。
  • array_combine:1つ目の配列を「キー」、2つ目の配列を「値」として組み合わせる。マージ(結合)ではなく別物。
  • Laravel Collection::merge():コレクションに対して array_merge と同様の挙動(数値キーは連番、文字列キーは後勝ち)を提供。ネイティブ配列ではなくコレクションを扱う場合はこちら。

テスト例(Pest)

<?php

it('overwrites string keys with the later array', function () {
    expect(array_merge(['a' => 1], ['a' => 2]))->toBe(['a' => 2]);
});

it('reindexes numeric keys from zero', function () {
    expect(array_merge([5 => 'x'], [3 => 'y']))->toBe([0 => 'x', 1 => 'y']);
});

it('keeps the first array on key collision with the + operator', function () {
    expect(['a' => 1] + ['a' => 2])->toBe(['a' => 1]);
});

it('does not merge nested arrays recursively', function () {
    $result = array_merge(['opts' => ['a' => 1]], ['opts' => ['b' => 2]]);
    expect($result)->toBe(['opts' => ['b' => 2]]);
});

it('flattens multiple arrays with spread', function () {
    $chunks = [['a', 'b'], ['c']];
    expect(array_merge(...$chunks))->toBe(['a', 'b', 'c']);
});

トラブルシュート(エラー別)

症状/エラー原因対処
Deprecated: array_merge(): Passing null to parameter #N ($arrays) of type array is deprecatedPHP 8.1以降で引数に null を渡したarray_merge($a, $b ?? []) のように ?? [] でフォールバックする
TypeError: array_merge(): Argument #N ($arrays) must be of type array, string given配列でない値(文字列・オブジェクトなど)を渡した渡す前に is_array() で確認するか、意図した配列に変換する
数値キーで管理していたIDと値の対応がズレたarray_merge は数値キーを再採番する仕様キーを保持したいなら + 演算子または array_replace を使う
ネストした連想配列の中身が期待通りマージされず丸ごと上書きされるarray_merge は1段のみで再帰しないarray_merge_recursivearray_replace_recursive を使う

関連記事

参考リンク

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする

コメント