array_mergeと+演算子の違い、数値キーが再採番されるか否か
array_mergeと+演算子はどちらも配列を結合しますが、数値キーはmergeが再採番・+が左優先、文字列キーはmergeが後勝ち・+が先勝ちと挙動が逆になります。
数値キーの扱いが正反対
配列を結合する手段として array_merge と + 演算子があって、どちらも似た顔をしていますが、数値キーの扱いが真逆なんですよね。ここを混同すると、要素が消えたり増えたりして頭を抱えることになります。まず数値キーの場合を見比べてみます。
$a = ['x', 'y']; // [0=>'x', 1=>'y']
$b = ['p', 'q']; // [0=>'p', 1=>'q']
var_dump(array_merge($a, $b));
// [0=>'x', 1=>'y', 2=>'p', 3=>'q'] ← 再採番されて全部残る
var_dump($a + $b);
// [0=>'x', 1=>'y'] ← キー0,1は左が優先、$bは捨てられる
array_merge は数値キーを振り直して全要素を連結します。一方 + は既存キーを左側優先で残すだけなので、右側の同キー要素は無視されます。この差が数値添字配列だと特に効いてきます。
文字列キーはどちらも左右で上書き方向が違う
文字列キーの場合は両方ともキーを保ちますが、衝突したときにどちらの値を採るかが逆になります。array_merge は後勝ち(右が上書き)、+ は先勝ち(左が残る)ですね。デフォルト値をベースにして一部だけ上書きしたい、といった用途で使い分けます。
$defaults = ['limit' => 10, 'sort' => 'asc'];
$input = ['limit' => 50];
var_dump(array_merge($defaults, $input));
// ['limit'=>50, 'sort'=>'asc'] ← 入力が既定を上書き(後勝ち)
var_dump($input + $defaults);
// ['limit'=>50, 'sort'=>'asc'] ← 入力が残り、足りない分を既定で補う(先勝ち)
設定のマージには+が便利なことが多い
「ユーザー指定を優先しつつ、指定のないキーは既定で埋める」というよくあるパターンは、$input + $defaults の形が簡潔で気に入っています。array_merge($defaults, $input) でも同じ結果になりますが、+ の方が「入力を主役に、足りない分を既定で補う」という意図が読み取りやすい気がします。ただし数値キーの設定だと + は落とし穴なので、そこだけ注意ですね。
function paginate(array $options): array
{
$defaults = ['page' => 1, 'perPage' => 20];
$options += $defaults; // 未指定キーだけ既定で補完
return [$options['page'], $options['perPage']];
}
まとめ
数値キーなら array_merge は再採番して全部残す、+ は左優先で右を捨てる。文字列キーなら array_merge は後勝ち、+ は先勝ち。この対応表を頭に入れておくと、どちらを使うか迷わなくなります。設定のデフォルト補完は + が読みやすい、というのが個人的な結論ですが、数値キーが混ざる配列では挙動を必ず確かめるようにしています。
よくある質問
Q. 数値キーではどう違いますか?
A. array_mergeは再採番して全要素を残し、+は左側のキーを優先して右側の同キー要素を捨てます。
Q. 文字列キーではどうですか?
A. array_mergeは後勝ち(右が上書き)、+は先勝ち(左が残る)と、上書きの方向が逆になります。
Q. 設定のデフォルト補完にはどちらが向きますか?
A. $input + $defaultsの形が、入力を主役に足りない分を既定で補う意図が読み取りやすいです。ただし数値キーが混ざる場合は挙動を確かめてください。