Webmaster Hub - Format normal - Les publications

[niveau : confirmé/expert]

Tester correctement variables et valeurs en php

Les problèmes de typage et de transtypage

7 septembre 2003

par Cariboo

Les publications de Webmaster Hub
http://www.webmaster-hub.com/publication/Tester-correctement-variables-et.html

Certains avantages du php, comme sa gestion très relâchée des types de variables, ont aussi quelques inconvénients. Mais une fois que l’on sait éviter et détecter ces problèmes, il est possible d’utiliser à son profit certaines particularités du langage pour écrire des scripts très puissants...

Comment prévenir les bogues dues aux problèmes de typage ?

En php, chaque variable peut changer de type en cours de route. Ce qui a pour conséquence de rendre le résultat de certains tests d’égalité imprévisibles

Bogues de comparaison entre types différents
Voici un bout de code courant qui peut poser problème

Si $var contient la chaine ’123’ au lieu du nombre 0, cette expression est considérée comme toujours vraie...

Solution : il faut donc penser à utiliser l’opérateur d’égalité === qui vérifie à la fois que les valeurs sont égales et qu’on ne compare pas des carottes et des navets

Bogues de typage des valeurs retournées par une fonction

Il arrive fréquemment que des fonctions renvoient une valeur numérique ou une chaine lorsque tout va bien, et le booléen "false" en cas d’échec : le résultat peut être ambigu... Exemple :

Ce code fonctionne à peu près bien en php3. Sauf quand la chaine renvoyée se trouve être "false" (bogue subtile).

En php4, si on écrit

Ce code peut toujours renvoyer false !

A l’inverse, le code :

ne fonctionnera pas correctement non plus, puisque le type peut être tantôt booléen, tantôt une chaine !

Un exemple plus spectaculaire

donne à l’écran
Solution : éviter les comparaisons inutiles entre booléens et valeurs true et false. Préférer if(!fonction($param)){$chaine=fonction($param);} à if(fonction($param)== true){$chaine=fonction($param);}.

Attention : de plus, plusieurs fonctions, qui renvoyaient une chaine "false" en cas de problème en php3, envoient un booléen false en php4, ce qui empêche certains scripts mis au point en php3 de tourner en php4

Comportement atypique des valeurs booléennes

Par ailleurs, pour des raisons obscures (au moins pour moi), le booleen "false/true" est stocké sous la forme d’un entier égal à 1 si la valeur est true, tandis que (en php3) la valeur false est stockée parfois sous la forme de l’entier 0, la valeur "null", ou la chaine ’’. Dans les versions récentes de php, ces ambiguïtés disparaissent.

Dans la pratique, cela n’a pas d’incidence notable dans les calculs, compte tenu de la conversion automatique des types en php. Ce qui fait que dans la pratique, si $exp1 est true et $exp2 est false, les calculs booléens suivants donnent les résultats attendus :
$exp1 * $exp2 est évaluée à 0 (false)
$exp1 + $exp2 est évaluée à 1 (true)

Mais il est intéressant de connaître cette particularité, car dans certains cas, le transtypage donne des résultats qui peuvent sembler étonnants, où les fonctions de conversion de type renvoyer des messages difficiles à comprendre sinon.

Par ailleurs, pour les transtypages, il est interessant de savoir comment s’évaluent différentes valeurs si elles sont converties en type booléen :

false -> false (heureusement !)
0 -> false
null -> false
0.0 -> false (attention : sources de bogues subtiles)
"" (chaîne vide) -> false
"0" -> false (attention : source de bogues subtiles)
tableau vide -> false
objet vide -> false
toutes les autres valeurs -> true

Donc 2 s’évalue comme true, et -1 aussi !

Solution générale : ne jamais utiliser d’égalité sans savoir à l’avance le type des variables ou des expressions comparées => utiliser les fonctions de test de typage avant

Utilisation de la valeur NULL

NULL est apparue avec le PHP4

NULL est une constante particulière. Affectée à une variable elle permet de "vider" celle-ci de sa (ses) valeurs. Elle reste déclarée, mais ne contient rien. Elle n’a plus son ancien type non plus (le type devient NULL).

Attention là aussi aux comparaisons entre valeurs dans le cas où une variable peut contenir la (non)valeur NULL

NULL == NULL est évalué true
NULL == FALSE est évalué true
NULL == TRUE est évalué false

Cette valeur NULL n’a rien à voir avec le NULL du langage SQL donc attention aux intuitions.

Par ailleurs, il est difficile de distinguer les variables de type NULL et les variables non déclarées ou supprimées avec unset()

Il faut utiliser le bon test

nouveau comportement de unset()

La fonction unset($var) permet de supprimer la variable de l’environnement. La variable $var n’est plus déclarée après cela. C’est utile par exemple pour supprimer d’un seul coup toutes les valeurs d’un tablo, avant de le redéfinir avec des indices différents...

unset() était une fonction en php3. Ce n’est plus le cas en php4, c’est devenu une structure du langage. Donc le test suivant ne marche pas en php4

Remarque : unset() ne fonctionne pas correctement au sein de fonctions avec des variables statiques. Les autres cases mémoires ne sont pas supprimées...

Philippe YONNET

Vous avez des questions ? Des réactions ? Vous avez remarqué une erreur ? Commentez l’article sur le forum Webmaster-hub