PHP et les pièges du typage faible

Le PHP est ce qu’on appelle un langage faiblement typé. Il permet au programmeur de ne pas se soucier du type de variables qu’il manipule (contrairement au Java et C# qui sont dits fortement typés). Si cela offre certaines facilités l’approche comporte toutefois certains pièges dont il vaut mieux être conscient.

Premier exemple: Entier et booléen

if (strpos('abcdefg','abc')){
    echo "trouvé!";
}else{
    echo "pas trouvé";  // Le code abouti ici
}

Le code ci-dessus affiche la chaine « pas trouvé ». La raison est que la fonction strpos() renvoi un entier pour indiquer la position de la deuxième chaîne dans la première. Dans ce cas de figure, l’entier est à 0 (zéro) qui est évalué par PHP comme étant un false.

Le manuel précise que strpos() renvoi un false booléen si la deuxième chaine n’est pas trouvée et on pourrait réécrire le code de la manière suivante.

if (strpos('abcdefg','abc') != false){
    echo "trouvé!";
}else{
    echo "pas trouvé";
}

Sauf que le 0 est toujours évalué comme un false. La solution si l’on souhaite continuer à utiliser le if tel quel est d’utiliser l’opérateur !== qui permet de différencier à la fois le type et la valeur d’une variable:

if (strpos('abcdefg','abc') !== false){
    echo "trouvé!";  // Le code abouti ici
}else{
    echo "pas trouvé";
}

Deuxième exemple: Comparaison non stricte et précision

var_dump(0123 == 123); // bool(false)
var_dump("0123" == 123); // bool(true)
var_dump(0.7 + 0.1 == 0.8); // bool(false)
var_dump('12abc' == 12); // bool(true)

Cas 1: 0123 est évalué comme une notation octale à cause du zéro en première position ce qui revient à la valeur 83 en base décimale.
Cas 2: « 0123 » est évalué comme une chaine de caractères à cause de la présence des guillemets. Ensuite, la chaine est converti en entier.
Cas 3: La comparaison donne false pour une question de précision et de représentation interne. Il est préférable d’éviter de comparer des nombres flottants.
Cas 4: Comme pour le deuxième cas, le premier argument est évalué comme une chaine de caractères puis converti en entier. Le résultat c’est que « abc » est tronqué.

Lorsque PHP effectue une comparaison avec l’opérateur non stricte (==) il effectue un transtypage des arguments en double. Cela peut donner des résultats inattendus lorsqu’il y a dépassement de capacité. Il est donc conseillé de faire attention lorsqu’on manipule des valeurs très grandes.

Comme exercice, vous pouvez tester les comparaisons entre des valeurs très grandes avec ou sans apostrophes (‘123456789…) en permutant entre les opérateurs de comparaison == et ===.

Troisième exemple: Evaluation d’un nom de constante non définie

//MA_CONSTANTE_NON_DEFINIE n'a pas été précisé
if (MA_CONSTANTE_NON_DEFINIE){
    echo "Laurie"; // Le code abouti ici  
}else{
    echo "Hardy";  // ... et non ici
}

On est ici dans un cas de figure très particulier. Ce code déclenche une erreur mais si la configuration a été réglée pour l’ignorer, MA_CONSTANTE_NON_DEFINIE est évalué comme un TRUE.

Si vous effectuez la transition d’autres langages ou si vous redécouvrez le PHP, j’espère que ceci vous évitera de tomber dans quelques pièges classiques.

– James Poulson.

2 réflexions au sujet de « PHP et les pièges du typage faible »

  1. Salut lionheart33806. C’est exacte. Je n’étais pas tout à fait certain de la manière dont PHP traite une suite de caractères continus en interne mais il semble bien qu’il interprète cela comme une chaine. Comme la valeur booléenne false est associée au zéro, toute suite de caractères est sans doute considéré comme un true (> 0 ).

  2. Sans pouvoir le tester maintenant, pour le dernier exemple, il me semble que PHP l’interprète en tant que chaine de caractères, et donc passe « true ».

Les commentaires sont fermés.