Signature
array_udiff_assoc(array $array, array ...$arrays, callable $value_compare_func): arrayPurpose
array_udiff_assoc() computes a difference between arrays, and it asks two questions about each entry of the first array: does another array have the same key, and does the value stored under that key count as equal? The key check is done by PHP itself. The value check is done by a callback that you supply. An entry is kept only if no other array has a matching key with a value your callback treats as equal.
This suits data that plain === or string comparison cannot judge well: case-insensitive text, records compared by one field, or numbers compared with a tolerance you define.
Signature
Parameters and defaults
$array: the array whose entries you want to filter. Nothing else is returned....$arrays: one or more arrays to compare against. Their extra entries never appear in the result.$value_compare_func: the last argument, a callable with the shapefunction (mixed $a, mixed $b): int. It must return a value below zero, zero, or above zero. Zero means "equal".
There are no default values. The callback is required and must come after all the arrays.
Return value and failures
The function returns a new array containing the entries from the first array that are not matched in any other array. Keys from the first array are preserved, so the result may not be a list. If everything is matched, you get an empty array.
Passing something that is not an array, or a value that is not callable, throws a TypeError. Your callback may also throw, and that exception propagates to the caller.
Example 1: case-insensitive values
Here strcasecmp is the callback. Key a exists in both arrays and Apple equals apple ignoring case, so it is removed. Key b matches but the values differ. Key c has no counterpart in the second array, because the other array uses d.
$expected = ['a' => 'Apple', 'b' => 'Banana', 'c' => 'Cherry'];
$actual = ['a' => 'apple', 'b' => 'Blueberry', 'd' => 'cherry'];
$diff = array_udiff_assoc($expected, $actual, 'strcasecmp');
echo json_encode($diff, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"b":"Banana","c":"Cherry"}
Example 2: the extra key check
The sibling function array_udiff() ignores keys. With the same values in a different order, it reports no difference, while array_udiff_assoc() sees that positions 0 and 1 hold different values.
$left = [10, 20, 30];
$right = [20, 10, 30];
$compare = fn(int $x, int $y): int => $x <=> $y;
echo json_encode(array_udiff($left, $right, $compare), JSON_FORCE_OBJECT), "\n";
echo json_encode(array_udiff_assoc($left, $right, $compare), JSON_FORCE_OBJECT), "\n";{}
{"0":10,"1":20}
Example 3: records and several arrays
Values can be arrays too. This callback compares stock records by their qty field. With several comparison arrays, an entry is dropped when it is matched in at least one of them.
$byQty = fn(array $x, array $y): int => $x['qty'] <=> $y['qty'];
$base = ['apple' => ['qty' => 3], 'pear' => ['qty' => 5], 'plum' => ['qty' => 7]];
$northStock = ['apple' => ['qty' => 3], 'pear' => ['qty' => 6]];
$southStock = ['plum' => ['qty' => 7]];
echo json_encode(array_udiff_assoc($base, $northStock, $southStock, $byQty), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"pear":{"qty":5}}
Edge cases
- Only the first array is filtered. Entries that exist only in the other arrays are ignored.
- One dimension only. Nested arrays are not compared recursively unless your callback does it.
- Keys come from PHP, not your callback. Numeric-string keys such as
"1"are already stored as integer keys, so they match1. The callback cannot make two different keys match. - The callback may see any pair of values. PHP sorts each array internally before comparing, so the callback must handle every value from every array in any order. A callback that assumes the first argument always comes from the first array is unreliable.
- Float results are truncated. The return value is cast to an integer, so
0.5becomes0and counts as equal. Prefer<=>over subtraction.
Common mistakes
- Returning a boolean. A callback like
fn($a, $b) => $a == $breturnstruefor equal values, which is1, meaning "greater". Equal values should return0. - Expecting a symmetric result.
array_udiff_assoc($a, $b, $f)andarray_udiff_assoc($b, $a, $f)usually differ. Run it both ways if you need both sides. - Using it when keys do not matter. If positions are irrelevant, use
array_udiff(). Otherwise reordered lists will look different. - Putting the callback first. Unlike
array_filter(), the callback is the last argument. - Writing an inconsistent comparison. A callback that does not behave like a proper ordering can give surprising results because of the internal sorting.
Related functions
array_diff()andarray_diff_assoc(): the built-in comparison versions.array_udiff(): callback for values, keys ignored.array_diff_uassoc(): callback for keys, built-in comparison for values.array_udiff_uassoc(): separate callbacks for values and keys.array_uintersect_assoc(): the intersection counterpart.
Recap
Use array_udiff_assoc() when an entry should count as present only if both its key and a value judged by your callback match. The callback returns an integer with zero meaning equal, the result keeps the first array's keys, and only the first array is filtered.
Tested examples
$expected = ['a' => 'Apple', 'b' => 'Banana', 'c' => 'Cherry'];
$actual = ['a' => 'apple', 'b' => 'Blueberry', 'd' => 'cherry'];
$diff = array_udiff_assoc($expected, $actual, 'strcasecmp');
echo json_encode($diff, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"b":"Banana","c":"Cherry"}
$left = [10, 20, 30];
$right = [20, 10, 30];
$compare = fn(int $x, int $y): int => $x <=> $y;
echo json_encode(array_udiff($left, $right, $compare), JSON_FORCE_OBJECT), "\n";
echo json_encode(array_udiff_assoc($left, $right, $compare), JSON_FORCE_OBJECT), "\n";
{}
{"0":10,"1":20}
$byQty = fn(array $x, array $y): int => $x['qty'] <=> $y['qty'];
$base = ['apple' => ['qty' => 3], 'pear' => ['qty' => 5], 'plum' => ['qty' => 7]];
$northStock = ['apple' => ['qty' => 3], 'pear' => ['qty' => 6]];
$southStock = ['plum' => ['qty' => 7]];
echo json_encode(array_udiff_assoc($base, $northStock, $southStock, $byQty), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
{"pear":{"qty":5}}