- カテゴリ: collection
- 掲載バージョン: Laravel 12・PHP 8.4
- 名前空間 / FQCN / コマンド:
Illuminate\Support\Collection::merge - 関連: union / concat / replace / mergeRecursive / put
- 変更履歴: 特記事項なし
要点(TL;DR)
- 用途:既存コレクションに別の配列/コレクションを“上書きマージ”する
- 最低限の使い方:
$merged = collect(['a' => 1])->merge(['a' => 9, 'b' => 2]); - よくある罠:
- 文字キーは上書き、数値キーは末尾に追加(再インデックス)
- 深い階層は結合しない(再帰マージではない)→
mergeRecursiveを検討 - 原則非破壊(新インスタンスを返す)。元は変わらない
概要
merge は、配列や別のコレクションを取り込み、新しいコレクションを返します。文字キーが重複した場合は引数側で上書きされ、数値キーは末尾へ追加されます。設定の上書き、デフォルト値への追記など“後勝ち”でまとめたい場面に向きます。
構文 / シグネチャ
// Illuminate\Support\Collection
public function merge(array|\Illuminate\Support\Collection|\Illuminate\Contracts\Support\Arrayable|iterable $items): static;
- 引数(表)
| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| $items | array | Collection | Arrayable | iterable | はい | なし | マージ対象。文字キーは上書き、数値キーは末尾追加 |
- 戻り値:
Collection(元とは別の新インスタンス) - 例外/副作用:不正型を渡すと
TypeErrorの可能性。ファイル/DB 等の副作用はなし
使用例
最小例
<?php
use Illuminate\Support\Collection;
$base = collect(['a' => 1, 'b' => 2]);
$added = ['b' => 20, 'c' => 3];
$merged = $base->merge($added);
// $merged: ['a' => 1, 'b' => 20, 'c' => 3]
// $base は変化しない
実務例:リクエスト値で設定を後勝ち上書き
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
function buildConfig(Request $request): array
{
$defaults = collect([
'paginate' => 20,
'order' => 'desc',
'filters' => ['status' => 'active'],
]);
// リクエストから上書き(filters は再帰マージされない点に注意)
$userInput = collect($request->only(['paginate', 'order', 'filters']));
return $defaults->merge($userInput)->all();
}
数値キーの追加(再インデックス)
<?php
$merged = collect([10, 20])->merge([30, 40]);
// 結果: [10, 20, 30, 40] (0,1,2,3 と再インデックス)
コレクション固有の補足
- チェーン可否:可(
Collectionを返す) - 破壊的/非破壊:非破壊(新しいコレクションを返す)
- キー保持:文字キーは上書き、数値キーは末尾追加(再インデックス)
- LazyCollection:キー上書きを伴うため全件評価になりやすい。大量データは
concatなどの惰性的手段を検討 - 計算量の目安:O(n + m)(n=元コレクション、m=マージ対象)
- 入出力対応表
| 入力A | 入力B | 結果 |
|---|---|---|
['a'=>1,'b'=>2] | ['b'=>9,'c'=>3] | ['a'=>1,'b'=>9,'c'=>3](b を上書き) |
[10,20] | [30,40] | [10,20,30,40](数値キーは追加) |
['f'=>['x'=>1]] | ['f'=>['y'=>2]] | ['f'=>['y'=>2]](深い階層は上書き) |
collect(['k'=>1]) | collect(['k'=>2,'n'=>0]) | ['k'=>2,'n'=>0] |
よくある落とし穴・注意
- 深い配列は結合されない:
['a'=>['x'=>1]]に['a'=>['y'=>2]]をmergeするとaは 丸ごと上書き。→ 再帰的に結合したいならmergeRecursive - 順序に意味がある場合:
unionは「元を優先」し、既存キーを上書きしない。後勝ちが不要ならunion - 大量データ:
mergeは全件を新インスタンスへ集約するためメモリ増。ストリーム処理はconcatやLazyCollectionの活用を検討 - JSON/Arrayable:
toArray()相当で取り込まれる想定のため、意図せぬ型変換に注意
代替・関連APIとの比較
union($items):キーが重複しても元の値を保持(上書きしない)。設定の“初期値優先”に最適concat($items):値を後ろに連結(キーは基本的に無視/再インデックス)。順序重視・大量データにreplace($items):キー一致の置換に特化(追加はしない)。既存キーのみ更新したいときmergeRecursive($items):深い階層も結合。ただし数値配列はネストが増えるなど期待と違う結果になり得る
テスト例(Pest)
<?php
use Illuminate\Support\Collection;
it('overwrites string keys and appends numeric keys', function () {
$base = collect(['a' => 1, 'b' => 2, 10, 20]);
$merged = $base->merge(['b' => 99, 'c' => 3, 30, 40]);
expect($merged->only(['a','b','c'])->all())
->toBe(['a' => 1, 'b' => 99, 'c' => 3]);
expect($merged->values()->all())
->toBe([1, 99, 10, 20, 30, 40]); // 値の配列としては末尾に追加
});
トラブルシュート(エラー別)
| 症状/エラー | 原因 | 対処 |
|---|---|---|
TypeError: merge(): Argument #1 must be ... | 渡した値が配列/反復可能でない | [] か collect() に包む/->all() で配列化して渡す |
| 深い配列が結合されず消えた | merge は非再帰のため上位キーごと上書き | mergeRecursive に切替/事前に array_replace_recursive 等で整形 |
| 期待と異なる順序になる | 数値キーは末尾追加・再インデックス | 順序重視は concat、またはキー付き配列にして制御 |
| 既存値を守りたいのに上書きされた | merge は後勝ち | union を使用 |

