array_udiff
Compares arrays by value using a callback and returns the values only present in the first array.
array_udiff(array $array, array ...$arrays, callable $value_compare_func): array- Added in PHP 5.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$array | array | The first array, whose values are the candidates for the result. |
$arrays | array | One or more arrays to compare against. Variadic. |
$value_compare_func | callable | Comparison 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
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.
<?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.
<?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.
<?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