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の形が、入力を主役に足りない分を既定で補う意図が読み取りやすいです。ただし数値キーが混ざる場合は挙動を確かめてください。

類似投稿

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です