Функция array_udiff_assoc() в PHP
Как работает array_udiff_assoc() в PHP: сравнение массивов по ключу и callback-функции значений. Синтаксис, примеры и подводные камни.
array_udiff_assoc() сравнивает два или более массивов и возвращает элементы из первого массива, которые отсутствуют в остальных. Её особенность — в способе сравнения: ключи сравниваются встроенной строгой проверкой, а значения — callback-функцией, которую вы передаёте. На этой странице разбирается сигнатура, рассматриваются рабочие примеры (строки, несколько массивов и объекты) и объясняются типичные ошибки.
Синтаксис
array_udiff_assoc(
array $array,
array ...$arrays,
callable $value_compare_func
): array$array— массив, из которого берутся элементы для сравнения. Только его элементы могут попасть в результат....$arrays— один или несколько массивов для сравнения с ним. Можно передавать сколько угодно.$value_compare_func— callback-функция, сравнивающая два значения. Она должна возвращать целое число меньше, равное или больше 0, когда первый аргумент соответственно меньше, равен или больше второго — тот же контракт, что используется вusort()и операторе «космический корабль» (<=>).
Функция возвращает новый array из сохранившихся пар ключ/значение из $array. Callback всегда является последним аргументом.
Принцип сравнения
Элемент из первого массива сохраняется, если ни в одном другом массиве нет одновременно того же ключа (сравниваемого внутренне как строки) и значения, которое callback считает равным (возвращает 0). Иными словами:
- Ключи → строгое встроенное сравнение (отражено в слове
assocв названии). - Значения → ваш callback (буква
uозначает user-defined, пользовательский).
Это главное отличие от array_diff_assoc(), который сравнивает значения через приведение к (string), и от array_udiff(), который полностью игнорирует ключи.
Базовый пример
<?php
function compareArrays($a, $b) {
if ($a === $b) {
return 0;
}
return ($a > $b) ? 1 : -1;
}
$array1 = array("a" => "red", "b" => "green", "c" => "blue");
$array2 = array("a" => "red", "b" => "blue", "c" => "green");
$result = array_udiff_assoc($array1, $array2, "compareArrays");
print_r($result);
?>Разбор по ключам:
a→"red"против"red": ключи совпадают, callback возвращает0(равны) → удалён.b→"green"против"blue": ключи совпадают, значения различаются → сохранён.c→"blue"против"green": ключи совпадают, значения различаются → сохранён.
Вывод:
Array
(
[b] => green
[c] => blue
)Сравнение с несколькими массивами
Можно передать более одного массива для сравнения. Элемент сохраняется, только если его нет ни в одном из остальных массивов. В примере ниже callback сравнивает строки сначала по длине, затем по алфавиту:
<?php
function compareValues($a, $b) {
return strlen($a) <=> strlen($b) ?: strcmp($a, $b);
}
$current = ["item1" => "apple", "item2" => "banana", "item3" => "kiwi"];
$baseline = ["item1" => "apple", "item2" => "cherry", "item3" => "kiwi"];
$result = array_udiff_assoc($current, $baseline, "compareValues");
print_r($result);
// Array
// (
// [item2] => banana
// )Отличается только item2: "banana" (6 букв) и "cherry" (6 букв) одинаковой длины, поэтому callback переходит к strcmp(), который сообщает о различии. item1 и item3 одинаковы в обоих массивах и удаляются.
Сравнение объектов
Настоящая сила array_udiff_assoc() проявляется, когда значениями являются объекты или массивы — то, что нельзя сравнить простым приведением к строке. Callback определяет смысл «равенства». В примере две корзины товаров сравниваются только по цене, без учёта названия товара:
<?php
class Product {
public function __construct(public string $name, public float $price) {}
}
function byPrice(Product $a, Product $b): int {
return $a->price <=> $b->price;
}
$cart = [
"p1" => new Product("Pen", 1.50),
"p2" => new Product("Notebook", 3.00),
];
$reference = [
"p1" => new Product("Pen", 1.50),
"p2" => new Product("Notebook", 4.25),
];
$diff = array_udiff_assoc($cart, $reference, "byPrice");
foreach ($diff as $key => $product) {
echo "$key => {$product->name} ({$product->price})\n";
}
// p2 => Notebook (3)У p1 цена в обоих массивах одинакова, поэтому он удаляется; цена p2 изменилась, значит, он сохраняется.
Подводные камни
- Callback — последний аргумент, а не второй. Распространённая ошибка — вызов
array_udiff_assoc($a, $callback, $b). Правильный порядок: первый массив, затем массивы для сравнения, затем callback. - Callback сравнивает значения, но не ключи. Ключи обрабатываются внутренне строгим сравнением; влиять на сопоставление ключей здесь нельзя. Если нужно пользовательское сравнение ключей, используйте
array_udiff_uassoc(). - Возвращайте целое число, а не boolean. Возврат
true/falseиз callback срабатывает случайно (они приводятся к1/0), но это ненадёжно — возвращайте результат<=>или явное-1/0/1. - В результате сохраняются оригинальные ключи из первого массива; переиндексация не выполняется.
Когда использовать
Используйте array_udiff_assoc(), когда важны и ключ, и пользовательское сравнение значений — например, при сравнении двух наборов объектов с ключами, поиске различий без учёта регистра с сохранением идентификаторов или вычислении изменений между предыдущим и текущим состоянием. Если ключи не важны, используйте array_udiff(); если значения — простые скаляры, достаточно более лёгкого array_diff_assoc().
Заключение
array_udiff_assoc() — точный инструмент для поиска различий между массивами, когда важны и ключи, и пользовательская логика сравнения значений. Сочетая строгое сопоставление ключей с управляемым callback-сравнением, можно сравнивать сложные структуры данных — объекты, вложенные массивы, нормализованные строки — без написания вложенных циклов и ручных проверок.