Collection::diff

Returns the items whose values are not present in the given array or collection.

Signature
diff(iterable|Arrayable $items): Collection
  • Added in Laravel 4.0

Parameters

ParameterTypeDescription
$$items\Illuminate\Contracts\Support\Arrayable<array-key, TValue>|iterable<array-key, TValue>The array, collection or Arrayable to compare against. Its keys are ignored entirely.

Return value

Collection<TKey, TValue>A new collection of the original items whose values do not appear in the given items, with the original keys preserved.

Changelog

  • PHP 5.xEloquent collections override diff() to compare models by primary key rather than by string value.

diff() answers "what do I have that they don't?" It returns the items from this collection whose values are absent from the argument. Order matters: $a->diff($b) and $b->diff($a) are different questions.

Values only, keys ignored

The comparison looks solely at values. Keys in the argument are irrelevant, and keys in the original are preserved in the result — so the output is usually sparse and json_encode() will render it as an object. Call values() when you need a packed list. Two sibling methods cover the other cases: diffKeys() compares by key, diffAssoc() by key and value together.

Everything is compared as a string

This is the trap. diff() delegates to PHP's array_diff(), which casts both sides to string before comparing. The integer 2 and the string '2' are therefore considered equal — convenient for ids from a request — but any value that cannot be cast to a string, such as an array, raises an error. On collections of arrays or plain objects, use reject() with an explicit predicate, or diffUsing() with a comparison callback.

Eloquent

Eloquent collections override this method to compare models by primary key, which is what you want for "which of these records were removed?".

Example

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

When to use it

  • Find which permission names a role is missing from a required set.
  • Detect ids present in an incoming payload but absent from the database.
  • Diff two tag lists to see which tags need to be removed.

Frequently asked questions

Does diff() compare keys or values?

Values only — keys in the argument are ignored, though the original collection's keys are preserved in the result. Use diffKeys() to compare by key and diffAssoc() to compare key and value together.

Why does diff() treat 2 and '2' as the same?

Because it delegates to PHP's array_diff(), which casts both operands to string before comparing. Use diffUsing() with a strict callback, or reject() with an explicit predicate, when the types must be distinguished.

Can I diff a collection of arrays or objects?

Not with diff() — array_diff() cannot cast them to strings and will error. Pluck a scalar identifier first, use diffUsing() with a comparison callback, or rely on an Eloquent collection's override that compares models by primary key.

More examples

diff, diffKeys and diffAssoc side by side

One dataset, three answers. diff() dropped remain because the value 6 exists somewhere in $other, even under a different key. diffKeys() found nothing because all three keys exist. diffAssoc() kept remain because 6 is not paired with the key remain on the other side — that is usually the comparison people actually want for settings or attributes.

Example · php
<?php

$current = collect([
    'color'  => 'orange',
    'type'   => 'fruit',
    'remain' => 6,
]);

$other = [
    'color'  => 'yellow',
    'type'   => 'fruit',
    'remain' => 3,
    'used'   => 6,
];

// Values only. 'orange' is absent from $other; 'fruit' and 6 are present
// (6 appears under 'used'), so only color survives.
print_r($current->diff($other)->all());
// Array ( [color] => orange )

// Keys only. Every key in $current also exists in $other.
print_r($current->diffKeys($other)->all());
// Array ( )

// Key AND value must both match to be excluded.
print_r($current->diffAssoc($other)->all());
// Array ( [color] => orange [remain] => 6 )

Syncing records with an Eloquent collection

The first half diffs plain strings and calls values() so the result is a packed list before iterating. The second half relies on the Eloquent override: two model instances of the same row compare equal by primary key, so the two diffs give exactly the ids to detach and attach. Needs a booted application with a database.

Example · php
<?php

$existing = Tag::whereIn('slug', $incoming)->get();

// Which incoming slugs have no row yet?
$missing = collect($incoming)->diff($existing->pluck('slug'))->values();

$missing->each(fn (string $slug) => Tag::create(['slug' => $slug]));

echo $missing->implode(', '), PHP_EOL;
// laravel, php-85

// Eloquent's diff() compares by primary key, not by string value.
$before = $post->tags;                 // saved tags
$after  = Tag::whereIn('id', $ids)->get();

$detach = $before->diff($after)->pluck('id');
$attach = $after->diff($before)->pluck('id');

$post->tags()->detach($detach);
$post->tags()->attach($attach);

Discussion

  • Be the first to comment on this lesson.