Collection::merge

Merges an array or collection into the collection, overwriting string keys and appending numeric ones.

Signature
public function merge(\Illuminate\Contracts\Support\Arrayable|iterable $items): static

Parameters

ParameterTypeDescription
$$items\Illuminate\Contracts\Support\Arrayable|iterableThe array, collection or other arrayable value to merge into this collection.

Return value

Illuminate\Support\CollectionA new collection containing the original items with the given items merged in.

merge is array_merge in collection clothing, and it inherits that function's split personality. String keys behave like a dictionary update: a matching key in the incoming data overwrites the existing value. Numeric keys behave like a list append: incoming values are added to the end and renumbered, never matched against existing positions.

When to reach for it

Layering configuration over defaults, adding computed fields onto a record before it is serialised, or joining two loaded result sets into one list. It accepts anything arrayable — a plain array, another collection, an Eloquent collection, or a model implementing Arrayable.

What trips people up

The numeric-key rule surprises almost everyone once. Merging [0 => 'Chair'] into a list does not replace item zero, and it does not deduplicate — you get both copies. Use union when you want existing keys to win, replace when you want numeric keys matched by position, and unique afterwards if duplicates matter.

The merge is also shallow. A nested array in the incoming data replaces the existing nested array wholesale rather than merging into it; mergeRecursive is the deep version, and it turns colliding scalars into arrays.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Layer user-supplied options over a defaults array before using them.
  • Attach computed fields to a record's array form before returning it from an API.
  • Concatenate two loaded result sets into a single collection for one pass of processing.

Frequently asked questions

Why did merging duplicate my items instead of replacing them?

Because the keys were numeric, and numeric keys are appended and renumbered rather than matched. Use replace() to overwrite by position, or key both collections first.

Does it merge nested arrays?

No, the merge is shallow and a nested array replaces the existing one wholesale. mergeRecursive() descends, but it combines colliding scalar values into arrays.

Can I merge another collection rather than an array?

Yes — the argument may be any iterable or Arrayable, including another collection or an Eloquent collection.

More examples

merge versus union versus replace

merge lets the incoming 'b' win (99) while union keeps the original (2). On the list, merge appends Sofa as a third item, whereas replace matches key 1 and swaps Chair for Sofa.

Example · php
<?php

$base = collect(['a' => 1, 'b' => 2]);
$incoming = ['b' => 99, 'c' => 3];

print_r($base->merge($incoming)->all());
print_r($base->union($incoming)->all());

$list = collect(['Desk', 'Chair']);
print_r($list->merge(['Sofa'])->all());
print_r($list->replace([1 => 'Sofa'])->all());

Shallow, not deep

The plain merge replaces the whole 'mail' array, so 'driver' disappears. mergeRecursive descends instead and, because both sides define 'port', turns that value into the array [25, 587] rather than overwriting it.

Example · php
<?php

$config = collect([
    'mail' => ['driver' => 'smtp', 'port' => 25],
    'debug' => false,
]);

print_r($config->merge(['mail' => ['port' => 587]])->all());
print_r($config->mergeRecursive(['mail' => ['port' => 587]])->all());

Adding computed fields to a model

The record is narrowed with only() and then extended with derived values. Because the keys are strings, the merge behaves as a straightforward update. It needs a booted application, so it is shown rather than executed.

Example · php
<?php

$payload = collect($order->toArray())
    ->only(['id', 'reference', 'total'])
    ->merge([
        'total_formatted' => number_format($order->total / 100, 2),
        'is_overdue' => $order->due_at->isPast(),
    ]);

return response()->json($payload);

Discussion

  • Be the first to comment on this lesson.