Arrays7 min readExamples run on PHP 8.5.10

array_udiff()

Learn how array_udiff() removes values found in other arrays using your own comparison callback, with examples, edge cases and common mistakes.

Signature

array_udiff(array $array, array ...$arrays, callable $value_compare_func): array

Purpose

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 of 0 means "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().

Example
<?php
$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";
Output
{"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.

Example
<?php
$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";
Output
[{"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.

Example
<?php
$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";
Output
{"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

  1. Putting the callback first. It must be the final argument, after every array.
  2. Returning a boolean. A callback like fn($a, $b) => $a == $b returns true for equal values, which becomes 1 ("greater"), the opposite of what you want. Return 0 for equal values, for example with <=>.
  3. Returning floats. A float return value is cast to an integer, so 0.5 becomes 0 and counts as equal. Use <=> or return an explicit -1, 0 or 1.
  4. 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.
  5. Assuming the callback sees pairs from matching positions. It compares arbitrary pairs of values, so it must not depend on position.
  • 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

Case-insensitive difference with strcasecmp
<?php
$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";
Output
{"1":"Banana","2":"Cherry"}
Comparing records by id
<?php
$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";
Output
[{"id":1,"name":"Ada"},{"id":3,"name":"Grace"}]
Several comparison arrays
<?php
$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";
Output
{"0":1,"3":4,"5":6}