KeiruaProd

I help my clients acquire new users and make more money with their web businesses. I have ten years of experience with SaaS projects. If that’s something you need help with, we should get in touch!
< Back to article list

Tester (correctement !) la présence d’une clé dans un tableau en PHP

La plupart du temps, pour tester si une clé est présente dans un tableau, il faut utiliser array_key_exists. Pourtant on trouve encore des empty et isset à sa place, en pensant que ces 3 fonctions sont interchangeables : ce n’est pas le cas. Fin 2016 on trouve encore des confusions, donc cet article me servira de référence pour les futures revues de code 🙂

Au premier coup d’oeil, on a pourtant l’impression qu’elles font la même chose :



$a = ['AB' => 12, 'CB' => 34];

// 2 cas nominaux :
echo "Cas nominal : La clé est présente dans le tableau".PHP_EOL;
echo (int)array_key_exists('AB', $a).PHP_EOL;
echo (int)isset($a['AB']).PHP_EOL;
echo (int)!empty($a['AB']).PHP_EOL;

echo "Cas nominal : La clé n'est pas présente dans le tableau".PHP_EOL;
echo (int)array_key_exists('YZ', $a).PHP_EOL;
echo (int)isset($a['YZ']).PHP_EOL;
echo (int)!empty($a['YZ']).PHP_EOL;

Ce bout de code produit la sortie suivate :

Cas nominal : La clé est présente dans le tableau
1
1
1
Cas nominal : La clé n'est pas présente dans le tableau
0
0
0

La sortie dans les cas nominaux est bien celle attendu, d’où la confusion, mais nous allons voir dans quels cas celà peut poser problème.

isset

Je trouve régulièrement ce genre de bouts de code pour tester si une clé existe dans un tableau :

if (isset($values['reason'])) {
    // do something with $values['reason']
}

Le problème, c’est que ce bout de code ne fait pas toujours ce que son auteur pense.

Selon la documentation, isset  » Retourne TRUE si var existe et a une valeur autre que NULL. FALSE sinon. « 

Donc si $values[‘reason’] existe mais que sa valeur est nulle, le code à l’intérieur du if ne sera pas exécuté, ce qui peut avoir des effets de bord pénibles.

empty

Un autre exemple de code qui peut poser problème ?

$exitCode = !empty($data['EXIT_CODE']) ? $data['EXIT_CODE'] : null

Nous allons voir pourquoi, dans certains cas, $exitCode vaudra null, ce qui n’est peut-être pas le comportement attendu.

Selon la documentation, empty: « Retourne FALSE si var existe *et est non-vide, et dont la valeur n’est pas zéro. *« 

 Ce qui suit est considéré comme étant vide :

    "" (une chaîne vide)
    0 (0 en tant qu'entier)
    0.0 (0 en tant que nombre à virgule flottante)
    "0" (0 en tant que chaîne de caractères)
    NULL
    FALSE
    array() (un tableau vide)
    $var; (une variable déclarée, mais sans valeur)

Le risque d’effet de bord, c’est si la valeur de $data[‘EXIT_CODE’] a une valeur « vide », par exemple 0 : à cause de la manière dont est écrit le test au début de cette section, $exitCode vaudra null et non 0, ce qui peut poser problème (par exemple si plus loin on teste si $exitCode === null).

On teste

Armé de nos connaissances précises sur le fonctionnement d’empty et isset, on peut écrire un bout de code pour voir qu’effectivement, dans certains cas le test n’aura pas le comportement attendu par le développeur qui veut tester la présence de la clé dans un tableau :

echo "Cas limite : la clé est présente mais vaut 0".PHP_EOL;
$b = ['EF' => 0];
echo (int)array_key_exists('EF', $b).PHP_EOL;
echo (int)isset($b['EF']).PHP_EOL;
echo (int)!empty($b['EF']).PHP_EOL;

Ce bout de code produit les sorties suivantes :

Cas limite : la clé est présente mais vaut 0
1
1
0

Quand la clé est présente mais vaut 0, !empty vaut false, car la valeur testée est (légitimement) vide.

Prenons un autre exemple, où la valeur est présente mais vaut null. Là isset également n’a pas le comportement que croyait le développeur.

echo "Cas limite : la clé est présente mais vaut null".PHP_EOL;
$c = ['GH' => null];
echo (int)array_key_exists('GH', $c).PHP_EOL;
echo (int)isset($c['GH']).PHP_EOL;
echo (int)!empty($c['GH']).PHP_EOL;

Cas limite : la clé est présente mais vaut null
1
0
0

Dans ce dernier exemple, seul array_key_exists a le comportement que veut le développeur.

bref

Ce comportment n’est pas un bug de PHP : il faut bien voir que les fonctions isset et empty ont ce comportement car c’est celui qu’on attend d’elles. En sont conçues pour celà. C’est leur usage qui est inadapté dans certains cas. Il s’est répandu à une époque où isset et empty étaient plus rapides qu’array_key_exist pour le test d’existence. Je ne sais pas si c’est encore le cas, mais ça n’a aucune importance : il faut bien comprendre que ce genre de micro-optimisations n’a pas de sens (optimisez les portions du code qui comptent d’abord !) et si vous voulez le faire quand même, faites le en comprenant les effets de bord et en vous assurant que vous les traitez comme il se doit.

Ceci étant dit, en général, si vous voulez tester qu’une clé est présente dans un tableau, utilisez **array_key_exists**. Le code de ce gist est disponible sur github pour refaire le test chez vous.