W3docs

Использование array_udiff_uassoc в PHP

Узнайте, как использовать PHP-функцию array_udiff_uassoc для вычисления разности двух или более массивов с пользовательскими функциями сравнения.

array_udiff_uassoc() вычисляет разность двух или более массивов, проверяя и ключи, и значения — при этом вы сами определяете, как сравниваются и те, и другие, передавая два собственных колбэка. Элемент из первого массива попадает в результат только в том случае, если ни один другой массив не содержит элемента, совпадающего с ним одновременно по ключу и значению, согласно вашим колбэкам.

На этой странице подробно описывается, как взаимодействуют два колбэка (это то, что большинство справочников обходит стороной), приводится работающий пример и объясняется, когда эта функция является правильным инструментом по сравнению с более простыми аналогами.

Что такое array_udiff_uassoc?

array_udiff_uassoc() возвращает записи из $array1, которые отсутствуют в любом из других массивов. В отличие от array_diff(), которая сравнивает только значения через приведение к строке, этот вариант проверяет ключи и значения вместе и делегирует оба сравнения пользовательским функциям — именно это означают два символа u в названии (udiff = пользовательское сравнение значений, uassoc = пользовательское сравнение ключей).

Сигнатура функции:

Синтаксис функции PHP array_udiff_uassoc

array_udiff_uassoc(
    array $array1,
    array $array2,
    array ...$arrays,        // one or more additional arrays
    callable $value_compare_func,
    callable $key_compare_func
): array

Два колбэка всегда являются последними двумя аргументами в следующем порядке: сначала сравнение значений, затем сравнение ключей. Всё, что стоит перед ними, является массивом. Результат — новый массив записей из $array1, прошедших сравнение, с сохранением их исходных ключей.

Как на самом деле происходит сопоставление. Для каждой записи из $array1 PHP перебирает остальные массивы в поисках записи, ключ которой является «равным» согласно $key_compare_func и значение которой является «равным» согласно $value_compare_func. Если такое совпадение найдено в любом другом массиве, запись исключается; иначе — сохраняется. Запись удаляется только тогда, когда оба сравнения фиксируют равенство.

Понимание функций сравнения

Каждый колбэк принимает два аргумента и должен возвращать целое число, точно так же, как компаратор сортировки:

  • Вернуть 0, если два элемента считаются равными.
  • Вернуть положительное целое, если первый «больше».
  • Вернуть отрицательное целое, если первый «меньше».

PHP интересует только то, равно ли возвращаемое значение 0 (равны) или нет, однако требуется последовательный трёхпутевой результат, так как функция выполняет внутреннюю сортировку. Оператор «космический корабль» <=> — самый удобный способ его написать:

$value_compare_func = fn($a, $b) => $a <=> $b;   // strict ordering
$key_compare_func   = fn($a, $b) => strcasecmp((string) $a, (string) $b); // case-insensitive keys

Поскольку вы определяете оба сравнения, можно делать то, что встроенные функции разности не умеют — например, сравнивать ключи без учёта регистра или сравнивать объекты по одному свойству.

Пример: базовое использование

<?php

function compare_values($a, $b) {
    if ($a === $b) {
        return 0;
    }
    return ($a > $b) ? 1 : -1;
}

function compare_keys($a, $b) {
    if ($a === $b) {
        return 0;
    }
    return ($a > $b) ? 1 : -1;
}

$array1 = array('a' => 'apple', 'b' => 'banana', 'c' => 'cherry', 'd' => 'durian');
$array2 = array('a' => 'apple', 'b' => 'game', 'c' => 'cherry');
$array3 = array('a' => 'apple', 'b' => 'door', 'c' => 'cherry', 'g' => 'durian');

$result = array_udiff_uassoc($array1, $array2, $array3,  'compare_values', 'compare_keys');

print_r($result);

?>

Здесь compare_values и compare_keys — обычные трёхпутевые компараторы. Вызов вычисляет разность $array1 относительно $array2 и $array3, оставляя только те записи, чей ключ и значение нигде не совпадают. Результат:

Array
(
    [b] => banana
    [d] => durian
)

Разберём, почему каждая запись сохраняется или исключается:

  • a => apple — исключена: в $array2 (и в $array3) есть тот же ключ a и то же значение apple.
  • b => bananaсохранена: в остальных массивах ключ b присутствует, но их значения — game / door, не banana. Значения различаются, поэтому совпадения нет.
  • c => cherry — исключена: совпадает в обоих других массивах.
  • d => durianсохранена: в $array3 есть значение durian, но под ключом g, а не d. Ключи различаются, поэтому совпадения нет.

Последний случай — самая суть функции: даже если значение durian встречается в другом массиве, ключ не совпадает, и запись остаётся. Функция сравнения только по значению, например array_udiff(), удалила бы её.

Пример: ключи без учёта регистра

Поскольку сравнение ключей вы определяете сами, можно игнорировать регистр ключей при строгом сравнении значений:

<?php

$wanted  = ['x' => 10, 'y' => 20, 'z' => 30];
$current = ['x' => 10, 'Y' => 20, 'z' => 99];

$result = array_udiff_uassoc(
    $wanted,
    $current,
    fn($v1, $v2) => $v1 <=> $v2,                       // values: strict ordering
    fn($k1, $k2) => strcasecmp((string) $k1, (string) $k2) // keys: case-insensitive
);

print_r($result);

Результат:

Array
(
    [z] => 30
)

x => 10 и y => 20 удалены (в current есть то же значение под ключом, совпадающим без учёта регистра), тогда как z => 30 сохранена, потому что в current стоит z => 99 — ключ совпадает, но значение 99 !== 30.

Когда использовать (и чем заменить)

Используйте array_udiff_uassoc() только тогда, когда вам нужна пользовательская логика для обоих — и ключей, и значений. Если требования скромнее, более простой аналог будет быстрее читаться и писаться:

Что нужно контролировать…Используйте
Только значения (колбэк), ключи игнорируютсяarray_udiff()
Значения (колбэк) + ключи через ===array_udiff_assoc()
Ключи (колбэк) + значения через ===array_diff_uassoc()
Ничего — простая разность по значениямarray_diff()

Распространённые ошибки

  • Порядок аргументов. Колбэки — два последних аргумента, сначала сравнение значений. Передача в неправильном порядке молча даёт неверные результаты без каких-либо ошибок.
  • Не менее двух массивов. Необходимо передать $array1, хотя бы один другой массив и затем оба колбэка — минимум пять аргументов.
  • Возвращайте int, а не bool. Возврат true/false из компаратора работает случайно (они приводятся к 1/0), но нарушает упорядочивание. Используйте <=> или явные -1/0/1.
  • Ключи сохраняются. В результате сохраняются исходные ключи из $array1; переиндексация не производится.

Если колбэки для вас новы, смотрите PHP Callback Functions, а для общего повторения массивов — PHP Arrays.

Заключение

array_udiff_uassoc() — наиболее гибкая из функций разности массивов в PHP: она сравнивает записи и по ключу, и по значению, передавая оба сравнения вашим собственным колбэкам. Запись из первого массива сохраняется только тогда, когда ни один другой массив не совпадает с ней по обоим критериям. Используйте её, когда встроенных правил сравнения (===, приведение к строке) недостаточно — например, для ключей без учёта регистра, значений с учётом локали или сравнения объектов по полю — и переходите к более простому варианту array_diff*, когда такая гибкость не нужна.

Практика

Практика
Какова функциональность функции array_udiff_uassoc в PHP?
Какова функциональность функции array_udiff_uassoc в PHP?
Was this page helpful?