array_udiff

Compares arrays by value using a callback and returns the values only present in the first array.

Signature
array_udiff(array $array, array ...$arrays, callable $value_compare_func): array
  • Added in PHP 5.0

Parameters

ParameterTypeDescription
$arrayarrayThe first array, whose values are the candidates for the result.
$arraysarrayOne or more arrays to compare against. Variadic.
$value_compare_funccallableComparison function with the signature callback(mixed $a, mixed $b): int. It must return an integer less than, equal to, or greater than zero when $a is respectively less than, equal to, or greater than $b. Always the last argument.

Return value

arrayAn array of the values from $array that are not present in any of the other arrays, with the original keys preserved.

Errors

Throws a TypeError if fewer than three arguments are supplied, if any array argument is not an array, or if the last argument is not callable.

array_udiff() answers "which values are in the first array but in none of the others", using a callback you supply instead of string comparison. Keys are ignored during the comparison but preserved in the result.

When to reach for it

Reach for it whenever array_diff() cannot do the job because your values are not strings. Diffing two lists of objects by id, comparing records by a single field, matching strings case-insensitively, or comparing floats with a tolerance are all natural fits. array_diff() compares (string)$a === (string)$b, which throws an error on objects without __toString() and flattens distinct objects into the same string when they do have one.

What trips people up

The callback goes last, after all the arrays — the reverse of how array_map() is written. Getting this wrong produces a TypeError.

The callback is a three-way comparator, not an equality test. Returning true/false makes it return 1/0, which the function reads as "greater than"/"equal", giving nonsense results. Use strcmp(), $a <=> $b, or an explicit int.

PHP sorts each array internally before diffing, so your callback is called with pairs from within a single array as well as across arrays, and in an unpredictable order. It must define a consistent total ordering for every value in every array — not just decide whether two things match.

Example

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

When to use it

  • Find which objects in a fresh API response are not in the cached list, comparing by id.
  • Diff two lists of email addresses case-insensitively.
  • Compare arrays of floats with a tolerance instead of exact equality.

Frequently asked questions

What is the difference between array_diff and array_udiff?

array_diff compares values by casting them to strings, while array_udiff calls your callback to decide. Use array_udiff for objects, floats, or any comparison a string cast would get wrong.

Why does array_udiff take the callback as the last argument?

Because the array parameters are variadic — any number of arrays can be compared, so the callback has to come after them. Passing it earlier throws a TypeError.

Does array_udiff compare keys?

No, it compares values only, though the keys of the surviving elements are preserved in the result. Use array_udiff_assoc if the keys must match too.

More examples

Case-insensitive difference

Only [email protected] survives, at its original key 1. strcasecmp is already a valid three-way comparator, so it can be passed directly as a string callable.

Example · php
<?php
$wanted = ['[email protected]', '[email protected]', '[email protected]'];
$known  = ['[email protected]', '[email protected]'];

$new = array_udiff($wanted, $known, 'strcasecmp');
print_r($new);

More than two arrays

Values present in any of the later arrays are removed, leaving 1.0 at key 0 and 3.0 at key 2. The comparison callback is still the final argument no matter how many arrays precede it.

Example · php
<?php
$all      = [1.0, 2.0, 3.0, 4.0];
$archived = [2.0];
$deleted  = [4.0];

$live = array_udiff($all, $archived, $deleted, fn($a, $b) => $a <=> $b);
print_r($live);

Comparing floats with a tolerance

1.0001 is treated as equal to 1.0 because the difference is inside the tolerance, so only 9.9 remains at key 2. Note the callback still falls back to a real ordering when the values are not close, which array_udiff needs for its internal sort.

Example · php
<?php
$measured = [1.0001, 2.5, 9.9];
$expected = [1.0, 2.5];

$cmp = fn($a, $b) => abs($a - $b) < 0.01 ? 0 : ($a <=> $b);
print_r(array_udiff($measured, $expected, $cmp));

Discussion

  • Be the first to comment on this lesson.