Функция array_udiff() в PHP
Как PHP array_udiff() сравнивает массивы с помощью пользовательского callback и возвращает значения только из первого массива. Примеры с числами и object.
array_udiff() вычисляет разность массивов, сравнивая их значения с помощью callback-функции, которую задаёте вы. Функция возвращает значения из первого массива, которые не найдены ни в одном из остальных массивов. Буква «u» в названии означает user-defined (пользовательская) — в отличие от array_diff(), которая сравнивает значения как string, array_udiff() позволяет вам самим определить, когда два значения считаются «равными».
На этой странице рассматриваются синтаксис функции, принцип работы callback, запускаемые примеры с числами и object, а также распространённые ошибки.
Когда использовать array_udiff()?
Используйте array_udiff(), когда стандартное сравнение в array_diff() недостаточно точное:
- Object.
array_diff()преобразует каждое значение в string. Object без метода__toString()нельзя сравнить таким образом, поэтому нужен callback, проверяющий свойство. - Пользовательское равенство. Вы хотите сравнение без учёта регистра, сравнение по одному полю или числовое сравнение с допуском.
- Смешанные или нормализованные данные. Вы хотите считать
"5",5и5.0одним значением или сравнивать числа с плавающей точкой с округлением.
Если нужно простое сравнение string, предпочтительнее использовать array_diff().
Как работает array_udiff()
Функция принимает два и более массива, причём последним аргументом является callback сравнения. Возвращается array значений из первого массива, которые callback не признаёт равными ни одному значению в последующих массивах. Ключи и порядок из первого массива сохраняются.
Синтаксис
array_udiff(array $array1, array $array2, array ...$arrays, callable $value_compare_func): arrayarray $array1— массив, значения которого возвращаются («базовый» массив).array $array2— массив для сравнения.array ...$arrays— любое количество дополнительных массивов для сравнения.callable $value_compare_func— callback сравнения. Всегда является последним аргументом.
Callback сравнения
Callback получает два значения и должен вернуть целое число:
- число меньше 0, если первое значение «меньше»,
- 0, если два значения считаются равными,
- число больше 0, если первое значение «больше».
Возврат 0 означает, что два значения равны, поэтому значение из $array1 исключается из результата, когда callback возвращает 0 при сравнении с каким-либо значением из последующего массива. Результаты < 0 / > 0 позволяют PHP внутренне сортировать значения для эффективного сравнения — важно возвращать их корректно, а не просто 0 или 1. Оператор spaceship (<=>) — самый простой и правильный способ получить это значение.
Пример 1: сравнение двух массивов чисел
В этом примере именованная функция используется как callback для поиска чисел, присутствующих в $array1, но отсутствующих в $array2:
<?php
function compare_numbers($a, $b) {
if ($a == $b) {
return 0;
} elseif ($a < $b) {
return -1;
} else {
return 1;
}
}
$array1 = [1, 2, 3, 4, 5];
$array2 = [2, 4, 6];
$result = array_udiff($array1, $array2, 'compare_numbers');
print_r($result);
?>compare_numbers() возвращает 0, когда два значения совпадают, поэтому совпавшие числа (2 и 4) удаляются. В результате сохраняются исходные ключи из $array1:
Array
(
[0] => 1
[2] => 3
[4] => 5
)Весь callback можно заменить однострочником с оператором spaceship: fn($a, $b) => $a <=> $b.
Пример 2: сравнение массивов object
Это тот случай, с которым array_diff() не справляется. Здесь мы сравниваем два массива object Product по их id и возвращаем продукты, отсутствующие во втором списке:
<?php
class Product {
public function __construct(public int $id, public string $name) {}
}
$catalog = [
new Product(1, 'Keyboard'),
new Product(2, 'Mouse'),
new Product(3, 'Monitor'),
];
$discontinued = [
new Product(2, 'Mouse'),
];
$available = array_udiff(
$catalog,
$discontinued,
fn(Product $a, Product $b) => $a->id <=> $b->id
);
foreach ($available as $product) {
echo $product->id . ': ' . $product->name . PHP_EOL;
}
?>Выводятся продукты, id которых отсутствует в $discontinued:
1: Keyboard
3: MonitorПоскольку callback сравнивает только id, различия в значениях name не имеют значения — логика сравнения полностью определяется вами.
Что важно помнить
- Callback всегда является последним аргументом, сколько бы массивов вы ни передали.
array_udiff()сравнивает значения. Для сравнения по ключам и значениям одновременно используйтеarray_udiff_assoc(); для сравнения ключей тоже с помощью callback —array_udiff_uassoc().- Возвращайте корректный трёхпозиционный результат (отрицательное /
0/ положительное), а не просто0или1. PHP использует порядок для эффективного сравнения, и небрежный callback может дать неверные результаты. - Результат сохраняет ключи и порядок
$array1. Вызовитеarray_values(), если нужен переиндексированный array. - В результате могут появляться только значения из первого массива — значения, уникальные для последующих массивов, никогда не возвращаются.
Связанные функции
array_diff()— та же идея, но с простым сравнением string.array_udiff_assoc()— callback для значений плюс сравнение ключей.array_uintersect()— эквивалент для пересечения (значения, присутствующие во всех массивах).- PHP Arrays и PHP Functions — основы.