PHPで配列をマージする方法まとめ【保存版】
2025/05/26 追記
PHP 7.4以降では 配列のアンパック を使って配列同士を結合する方法もあります。
配列のアンパックを使って2つの配列 $a
と $b
を結合した新たな配列 $c
を得るには、次のように書くことができます。
$c = [...$a, ...$b]
アンパックによる配列の結合は array_merge()
による配列の結合と動作としては等価です。
PHPで配列をマージ(結合)する方法は3通りあります。
-
+
演算子を使って配列同士を加算する -
array_merge()
を使う -
array_merge_recursive()
を使う
それぞれで微妙に挙動が違っていてとても紛らわしいので、可能な限り分かりやすく整理してみたいと思います。
方法ごとのポイント
+
による加算
- 同じキーがある場合は 先勝ち (前の配列の値が残って、後ろの配列の値が無視される)
- 「同じキー」と見なすのは、 数値キーと文字列キーの両方
- 一次元めのキーしか見られず、 二次元め以降の配列の構造は変化しない
array_merge()
による結合
- 同じキーがある場合は 後勝ち (第一引数の配列の値が第二引数の配列の値で上書きされる)
- 「同じキー」と見なすのは、 文字列キーのみ
- 数値キーの部分はすべて別物として扱われ、新しい配列では 数値キーが0から始まる連番で振り直される
- 一次元めのキーしか見られず、 二次元め以降の配列の構造は変化しない
array_merge_recursive()
による結合
- 同じキーがある場合は、新しい配列では そのキーの値が「それぞれの値を結合した配列」になる
- 「同じキー」と見なすのは、 文字列キーのみ
- 数値キーの部分はすべて別物として扱われ、新しい配列では 数値キーが0から始まる連番で振り直される
- 二次元め以降の配列も、同じキーがあれば 再帰的に結合される
- 同じキーの値を結合する際にも、これらのルールが適用される
とんでもなくややこしいですね…😓
具体例を見ながらもう少し詳しく確認してみましょう。
動作結果の例
例1(数値キーの振る舞い)
元の配列
$a = [
'a0',
'a1',
'a2',
];
$b = [
0 => 'b0',
1 => 'b1',
100 => 'b100',
];
結合後の配列
+
による加算では以下のようになります。
$a + $b === [
0 => 'a0',
1 => 'a1',
2 => 'a2',
100 => 'b100',
];
- 同じ数値キーを持つ要素が上書きされている
- 上書きされる際、 先勝ち で
$a
の値が残っている - 異なる数値キーを持つ要素はそのまま残っている
- 元の配列の数値キーがそのまま維持されている
また、地味ですが、この動作結果から「キーを明示しない配列で暗黙的に振られた数値キー」は「明示的に指定した数値キー」と完全に等価であることも分かりますね。
array_merge()
による結合では以下のようになります。
array_merge($a, $b) === [
0 => 'a0',
1 => 'a1',
2 => 'a2',
3 => 'b0',
4 => 'b1',
5 => 'b100',
];
- 同じ数値キーを持つ要素は別物扱い で、上書きされていない
- 元の数値キーは失われて 0から始まる連番でキーが振り直されている
array_merge_recursive()
による結合では以下のようになります。
array_merge_recursive($a, $b) === [
0 => 'a0',
1 => 'a1',
2 => 'a2',
3 => 'b0',
4 => 'b1',
5 => 'b100',
];
-
同じ数値キーは別物扱いなので、
array_merge()
とまったく同じ結果になっている
例2(文字列キーの振る舞い)
元の配列
$a = [
'key0' => 'a0',
'key1' => 'a1',
'key2-a' => 'a2',
];
$b = [
'key0' => 'b0',
'key1' => 'b1',
'key2-b' => 'b2',
];
結合後の配列
+
による加算では以下のようになります。
$a + $b === [
'key0' => 'a0',
'key1' => 'a1',
'key2-a' => 'a2',
'key2-b' => 'b2',
];
- 同じキーを持つ要素が上書きされている
- 上書きされる際、 先勝ち で
$a
の値が残っている - 異なるキーを持つ要素はそのまま残っている
array_merge()
による結合では以下のようになります。
array_merge($a, $b) === [
'key0' => 'b0',
'key1' => 'b1',
'key2-a' => 'a2',
'key2-b' => 'b2',
];
- 同じキーを持つ要素が上書きされている
- 上書きされる際、 後勝ち で
$b
の値が残っている - 異なるキーを持つ要素はそのまま残っている
array_merge_recursive()
による結合では以下のようになります。
array_merge_recursive($a, $b) === [
'key0' => [
0 => 'a0',
1 => 'b0',
],
'key1' => [
0 => 'a1',
1 => 'b1',
],
'key2-a' => 'a2',
'key2-b' => 'b2',
];
- 同じキーを持つ要素が 上書きではなく結合されている
- 異なるキーを持つ要素はそのまま残っている
例3(二次元配列の振る舞い)
元の配列
$a = [
'key' => [
'a0',
'a1',
],
];
$b = [
'key' => [
'b0',
'b1',
],
];
結合後の配列
+
による加算では以下のようになります。
$a + $b === [
'key' => [
0 => 'a0',
1 => 'a1',
],
];
- 一次元めで同じキーを持つ要素が上書きされている
- 上書きされる際、 先勝ち で
$a
の値が残っている - 二次元めの配列構造は「勝ったほうの配列」のまま何も変化していない
array_merge()
による結合では以下のようになります。
array_merge($a, $b) === [
'key' => [
0 => 'b0',
1 => 'b1',
],
];
- 一次元めで同じキーを持つ要素が上書きされている
- 上書きされる際、 後勝ち で
$b
の値が残っている - 二次元めの配列構造は「勝ったほうの配列」のまま何も変化していない
array_merge_recursive()
による結合では以下のようになります。
array_merge_recursive($a, $b) === [
'key' => [
0 => 'a0',
1 => 'a1',
2 => 'b0',
3 => 'b1',
],
];
- 一次元めで同じキーを持つ要素が 上書きではなく結合されている
- 二次元めの配列構造において、 数値キーは0から始まる連番で振り直されている
要するに何に気をつければいいのか
方法ごとの詳細な振る舞いを確認してきましたが、要するに何に気をつければいいかと言うと、
-
array_merge()
やarray_merge_recursive()
では数値キーをリセットされてしまうので、 数値キーに意味を持たせている配列の結合には使えない - 代わりに
+
による加算を使う場合、 「先勝ち」「後勝ち」が逆なので気を付ける - 数値キーをリセットせずに再帰的に結合したい場合は、自力でループを書くしかない
というところだと思います。
数値キーに意味を持たせている配列というのは、例えば
id
をキーにしたエンティティの配列などがよくあるパターンでしょう。
まとめ
- PHPで配列をマージ(結合)する方法は、
+
による加算、array_merge()
、array_merge_recursive()
の3通り - それぞれで 「先勝ち」「後勝ち」 が違っていたり、 数値キーがリセットされる/されない が違っていたりするので気を付ける
- 特に「数値キーに意味を持たせている配列」をマージする際に注意が必要
Discussion