La fonction array_udiff_assoc() de PHP expliquée
Découvrez array_udiff_assoc() en PHP : diff de tableaux par clé et callback personnalisé. Syntaxe, exemples, objets et pièges courants.
array_udiff_assoc() compare deux tableaux ou plus et renvoie les entrées du premier tableau qui n'apparaissent dans aucun des autres. Ce qui la rend spéciale, c'est la façon dont elle compare : les clés sont comparées par une vérification stricte intégrée, tandis que les valeurs sont comparées par une fonction de rappel que vous fournissez. Cette page explique la signature, parcourt des exemples concrets (chaînes, tableaux multiples et objets) et couvre les pièges qui font trébucher les développeurs.
Syntaxe
array_udiff_assoc(
array $array,
array ...$arrays,
callable $value_compare_func
): array$array— le tableau à comparer depuis. Seules ses entrées peuvent apparaître dans le résultat....$arrays— un ou plusieurs tableaux à comparer contre. Vous pouvez en passer autant que vous le souhaitez.$value_compare_func— un callback qui compare deux valeurs. Il doit retourner un entier inférieur à, égal à, ou supérieur à 0 lorsque le premier argument est respectivement considéré comme inférieur à, égal à, ou supérieur au second — le même contrat utilisé parusort()et l'opérateur spaceship (<=>).
Elle renvoie un nouveau tableau des paires clé/valeur survivantes de $array. Le callback est toujours le dernier argument.
Fonctionnement de la comparaison
Une entrée du premier tableau est conservée sauf si un autre tableau possède à la fois la même clé (comparée en interne sous forme de chaînes) et une valeur que le callback considère comme égale (retourne 0). En d'autres termes :
- Clés → comparaison stricte intégrée (le
assocdans le nom). - Valeurs → votre callback (le
u, pour user-defined).
C'est la différence essentielle avec array_diff_assoc(), qui compare les valeurs par transtypage (string), et avec array_udiff(), qui ignore complètement les clés.
Exemple de base
<?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);
?>Analyse clé par clé :
a→"red"vs"red": les clés correspondent, le callback retourne0(égal) → supprimé.b→"green"vs"blue": les clés correspondent, les valeurs diffèrent → conservé.c→"blue"vs"green": les clés correspondent, les valeurs diffèrent → conservé.
La sortie est donc :
Array
(
[b] => green
[c] => blue
)Comparaison avec plusieurs tableaux
Vous pouvez passer plus d'un tableau à comparer. Une entrée survit uniquement si elle est absente de chaque autre tableau. Ici, le callback compare les chaînes d'abord par longueur, puis alphabétiquement :
<?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
// )Seul item2 diffère : "banana" (6 lettres) et "cherry" (6 lettres) ont la même longueur, donc le callback passe à strcmp(), qui les signale comme différentes. item1 et item3 sont identiques dans les deux tableaux et sont supprimés.
Comparaison d'objets
La véritable puissance de array_udiff_assoc() se manifeste lorsque les valeurs sont des objets ou des tableaux — des éléments que vous ne pouvez pas comparer avec un simple transtypage en chaîne. Le callback décide de ce que signifie « égal ». Ici, deux paniers sont comparés uniquement par prix, en ignorant le nom du produit :
<?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 a le même prix dans les deux paniers et est supprimé ; le prix de p2 a changé, donc il survit.
Pièges courants
- Le callback est le dernier argument, pas le deuxième. Une erreur fréquente est d'appeler
array_udiff_assoc($a, $callback, $b). L'ordre est toujours : premier tableau, puis les tableaux à comparer, puis le callback. - Le callback compare les valeurs, pas les clés. Les clés sont gérées en interne par comparaison stricte ; vous ne pouvez pas influencer la correspondance des clés ici. Si vous avez besoin d'une comparaison de clés personnalisée également, utilisez
array_udiff_uassoc(). - Retournez un entier, pas un booléen. Retourner
true/falsedepuis le callback fonctionne par accident (ils sont transtypés en1/0) mais c'est fragile — retournez le résultat de<=>ou un-1/0/1explicite. - Le résultat conserve les clés d'origine du premier tableau ; il ne réindexe pas.
Quand l'utiliser
Utilisez array_udiff_assoc() lorsque la clé et une comparaison de valeur personnalisée importent toutes les deux — par exemple, pour différencier deux jeux de données indexés d'objets, comparer des enregistrements sans sensibilité à la casse tout en conservant leurs identifiants, ou calculer ce qui a changé entre un état précédent et l'état actuel. Si les clés ne comptent pas, utilisez array_udiff() ; si vos valeurs sont de simples scalaires, le plus léger array_diff_assoc() est généralement suffisant.
Conclusion
array_udiff_assoc() est un outil précis pour trouver les différences entre des tableaux lorsque les clés et une logique de valeur personnalisée importent. En combinant une correspondance stricte des clés avec un callback de comparaison que vous contrôlez, vous pouvez différencier des structures de données complexes — objets, tableaux imbriqués, chaînes normalisées — sans écrire de boucles imbriquées ni de vérifications manuelles.