Signature
array_udiff(array $array, array ...$arrays, callable $value_compare_func): arrayPurpose
array_udiff() returns the values of the first array that do not appear in any of the other arrays. Unlike array_diff(), which uses PHP's built-in string comparison, it lets you decide what "the same value" means by supplying a comparison callback. That makes it useful for case-insensitive matching, comparing records by an ID field, or comparing objects by a property.
Signature
Parameters and defaults
$array: the array whose values you want to filter. Its order and keys are used for the result....$arrays: one or more arrays to compare against. A value is removed from the result if the callback reports it as equal to a value in any of these arrays.$value_compare_func: the callback, which must be the last argument. It receives two values and must return an integer that is negative, zero or positive, just like a sort comparator. A return value of0means "equal".
There are no default values. You must pass at least the first array and the callback.
Return value and failure cases
The function returns an array containing the entries of the first array that have no match in the other arrays. Keys from the first array are preserved. If the callback is missing or is not callable, PHP raises an error (a TypeError for an invalid callback), so check the argument order when you see one.
Example 1: case-insensitive difference
The callback can wrap an existing comparison function such as strcasecmp().
$a = ["Apple", "Banana", "Cherry", "date"];
$b = ["apple", "DATE"];
$result = array_udiff($a, $b, fn($x, $y) => strcasecmp($x, $y));
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"1":"Banana","2":"Cherry"}
The keys 1 and 2 survive, which is why the JSON output is an object rather than a list.
Example 2: comparing records by one field
When values are arrays or objects, compare only the field that identifies them. The other fields are ignored.
$all = [
["id" => 1, "name" => "Ada"],
["id" => 2, "name" => "Linus"],
["id" => 3, "name" => "Grace"],
];
$done = [
["id" => 2, "name" => "ignored"],
];
$pending = array_udiff($all, $done, fn(array $a, array $b): int => $a["id"] <=> $b["id"]);
echo json_encode(array_values($pending), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";[{"id":1,"name":"Ada"},{"id":3,"name":"Grace"}]
Here array_values() re-indexes the result so it prints as a plain list.
Example 3: several comparison arrays
You can pass more than one array to compare against. A value is dropped if it matches in any of them.
$numbers = [1, 2, 3, 4, 5, 6];
$evenSmall = [2, 3];
$five = [5];
$result = array_udiff($numbers, $evenSmall, $five, fn($x, $y) => $x <=> $y);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"0":1,"3":4,"5":6}
The original keys 0, 3 and 5 are kept.
Edge cases
- Keys are preserved. Call
array_values()afterwards if you need a zero-based list. - Only values are compared. Keys play no part. If keys matter, look at
array_udiff_assoc(). - Duplicates in the first array that have no match are all kept; the function does not deduplicate.
- An empty first array gives an empty result, and empty comparison arrays remove nothing.
- One dimension only. Nested arrays are not compared recursively unless your callback does that work.
- Mixed types are your responsibility. The callback may receive any value from any of the arrays, in any order, because PHP sorts each array internally before comparing. It must handle all of them safely.
Common mistakes
- Putting the callback first. It must be the final argument, after every array.
- Returning a boolean. A callback like
fn($a, $b) => $a == $breturnstruefor equal values, which becomes1("greater"), the opposite of what you want. Return0for equal values, for example with<=>. - Returning floats. A float return value is cast to an integer, so
0.5becomes0and counts as equal. Use<=>or return an explicit-1,0or1. - Writing an inconsistent comparator. Tolerance-based rules such as "equal if within 0.1" are not transitive and can give unpredictable results, because the function relies on sorting.
- Assuming the callback sees pairs from matching positions. It compares arbitrary pairs of values, so it must not depend on position.
Related functions
array_diff(): difference using standard string comparison.array_diff_assoc(): difference that also requires keys to match.array_udiff_assoc(): callback for values, built-in comparison for keys.array_udiff_uassoc(): separate callbacks for values and keys.array_uintersect(): the intersection counterpart with a value callback.
Recap
Use array_udiff() when equality is defined by your own rule. Put the callback last, return a proper integer (<=> is ideal), expect keys to be preserved, and remember that values from the first array are removed when any other array contains a match under your callback.
Tested examples
$a = ["Apple", "Banana", "Cherry", "date"];
$b = ["apple", "DATE"];
$result = array_udiff($a, $b, fn($x, $y) => strcasecmp($x, $y));
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"1":"Banana","2":"Cherry"}
$all = [
["id" => 1, "name" => "Ada"],
["id" => 2, "name" => "Linus"],
["id" => 3, "name" => "Grace"],
];
$done = [
["id" => 2, "name" => "ignored"],
];
$pending = array_udiff($all, $done, fn(array $a, array $b): int => $a["id"] <=> $b["id"]);
echo json_encode(array_values($pending), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
[{"id":1,"name":"Ada"},{"id":3,"name":"Grace"}]
$numbers = [1, 2, 3, 4, 5, 6];
$evenSmall = [2, 3];
$five = [5];
$result = array_udiff($numbers, $evenSmall, $five, fn($x, $y) => $x <=> $y);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"0":1,"3":4,"5":6}