Signature
array_udiff_uassoc(
array $array,
array ...$arrays,
callable $value_compare_func,
callable $key_compare_func
): arrayPurpose
array_udiff_uassoc() returns the entries of the first array that have no match in any of the other arrays. An entry only counts as a match when both its value and its key are considered equal. Unlike array_diff_assoc(), you decide what "equal" means for both parts: one callback compares values and a second callback compares keys.
Use it when plain ===-style comparison is too strict, for example when keys differ only by case, or when values are records that should be matched by an identifier.
Signature
Parameters
$array: the array whose entries are tested. Its keys are preserved in the result....$arrays: one or more arrays to compare against.$value_compare_func: receives two values and returns an integer that is negative, zero or positive. Zero means the values are equal.$key_compare_func: receives two keys and follows the same contract. Zero means the keys are equal.
The two callbacks are always the last two arguments, in that order. There are no default values; all parts are required apart from the extra comparison arrays.
Return value and failures
The function returns an array with every entry from $array that is not matched in any other array. If everything is matched, the result is an empty array. The input arrays are never modified.
Passing something that is not an array or not a callable where one is required results in a TypeError. Exceptions thrown inside a callback propagate to your code.
Example 1: case-insensitive values and keys
Here both callbacks are strcasecmp, so 'a' and 'A' are the same key, and 'Apple' and 'apple' are the same value.
$a = ['a' => 'Apple', 'b' => 'Banana', 'c' => 'Cherry'];
$b = ['A' => 'apple', 'b' => 'Blueberry', 'd' => 'cherry'];
$result = array_udiff_uassoc($a, $b, 'strcasecmp', 'strcasecmp');
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"b":"Banana","c":"Cherry"}
Apple is removed because both key and value match. Banana stays because its key matches but its value does not. Cherry stays because no key in $b equals c, even though the value matches d.
Example 2: matching records by id against several arrays
When values are arrays, the value callback can compare just the field that identifies a record. With several comparison arrays, an entry is dropped if any one of them matches it.
$current = [
10 => ['id' => 1, 'name' => 'Ana'],
11 => ['id' => 2, 'name' => 'Ben'],
12 => ['id' => 3, 'name' => 'Cy'],
];
$archived = [
10 => ['id' => 1, 'name' => 'Old Ana'],
12 => ['id' => 9, 'name' => 'Other'],
];
$blocked = [
11 => ['id' => 2, 'name' => 'Blocked'],
];
$result = array_udiff_uassoc(
$current,
$archived,
$blocked,
fn(array $x, array $y): int => $x['id'] <=> $y['id'],
fn(int $x, int $y): int => $x <=> $y
);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"12":{"id":3,"name":"Cy"}}
Key 10 matches in $archived, key 11 matches in $blocked, but key 12 has different ids, so only that entry survives.
Example 3: absolute values and case-insensitive keys
$a = ['Mon' => 5, 'Tue' => -3, 'Wed' => 8];
$b = ['mon' => -5, 'tue' => 3, 'WED' => 7];
$result = array_udiff_uassoc(
$a,
$b,
fn(int $x, int $y): int => abs($x) <=> abs($y),
'strcasecmp'
);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"Wed":8}
Only Wed remains, because 8 and 7 have different absolute values.
Edge cases
- Keys are preserved. The result keeps the original keys from the first array; nothing is renumbered.
- Only the first array contributes entries. Entries that exist only in later arrays never appear in the result.
- Callbacks must be consistent. Each array is sorted internally before comparison, so a callback may receive any value from any array in any order. It must give a coherent ordering for everything it can see.
- Only one dimension is checked. Nested arrays are not compared recursively unless your callback does that work.
- Mixed types. If arrays hold different kinds of values, your callback must handle every combination.
Common mistakes
- Returning a boolean or float. The callbacks must return an integer. A float such as
0.5is cast to0and reads as "equal". A boolean from==givestrue(1) for equal values, which is the opposite of what you want. Use the spaceship operator<=>orstrcmp-style functions. - Swapping the callbacks. The value callback comes first and the key callback second. Reversing them compares keys with your value logic.
- Expecting key-only or value-only matching. Both must match for an entry to be removed. If you need only values, use
array_udiff(); if keys use the built-in comparison, usearray_udiff_assoc(). - Writing an order-dependent callback. A callback that assumes the first argument always comes from the first array can produce wrong results.
- Assuming deep comparison. For nested data, compare the relevant inner field explicitly.
Related functions
array_diff()andarray_diff_assoc()for built-in comparisonsarray_udiff()for a custom value callback onlyarray_udiff_assoc()for a custom value callback and built-in key comparisonarray_diff_uassoc()for built-in value comparison and a custom key callbackarray_uintersect_uassoc()for the intersection counterpart
Recap
array_udiff_uassoc() keeps the entries of the first array whose value and key pair is not matched in any other array, using two integer-returning callbacks you provide: values first, keys second. Keep the callbacks consistent, return real integers, and remember that keys are preserved.
Tested examples
$a = ['a' => 'Apple', 'b' => 'Banana', 'c' => 'Cherry'];
$b = ['A' => 'apple', 'b' => 'Blueberry', 'd' => 'cherry'];
$result = array_udiff_uassoc($a, $b, 'strcasecmp', 'strcasecmp');
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"b":"Banana","c":"Cherry"}
$current = [
10 => ['id' => 1, 'name' => 'Ana'],
11 => ['id' => 2, 'name' => 'Ben'],
12 => ['id' => 3, 'name' => 'Cy'],
];
$archived = [
10 => ['id' => 1, 'name' => 'Old Ana'],
12 => ['id' => 9, 'name' => 'Other'],
];
$blocked = [
11 => ['id' => 2, 'name' => 'Blocked'],
];
$result = array_udiff_uassoc(
$current,
$archived,
$blocked,
fn(array $x, array $y): int => $x['id'] <=> $y['id'],
fn(int $x, int $y): int => $x <=> $y
);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"12":{"id":3,"name":"Cy"}}
$a = ['Mon' => 5, 'Tue' => -3, 'Wed' => 8];
$b = ['mon' => -5, 'tue' => 3, 'WED' => 7];
$result = array_udiff_uassoc(
$a,
$b,
fn(int $x, int $y): int => abs($x) <=> abs($y),
'strcasecmp'
);
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"Wed":8}