Webmaster Hub - Format normal - Les publications
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...
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
if ($var==0){}
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 :
if (fonctionquelconquerenvoyantunechaine($chaine)=="false"){}
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
if (fonctionquelconquerenvoyantunechaine($chaine)== false){}
A l’inverse, le code :
if (fonctionquelconquerenvoyantunechaine($chaine)=== true){}
Un exemple plus spectaculaire
$var = true ;
if( $var == "true" ) echo("C'est vrai !"); // la chaine true est vraie car non vide donc le test d'égalité renvoie vrai !
if( $var == "false" ) echo("C'est faux !") // même chose, sauf que là, l'affichage devient plus étonnant
if( $var == "caribou" ) echo("C'est un cariboo !"); // cela marche avec n'importe qu'elle chaîne
if( $var == 4 ) echo("C'est le nombre 4!") ; // cela marche aussi avec un type numérique. 4 est vrai !
C'est vrai !
C'est faux !
C'est un caribou !
C'est le nombre 4 !
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
//$var est NULL
($var) renvoie TRUE
isset($var) renvoie FALSE
empty($var) renvoie TRUE
is_null($var) renvoie TRUE
//$inexistante est une variable inexistante ou supprimée par unset()
($var) renvoie FALSE
isset($inexistante) renvoie FALSE
empty($novar) renvoie TRUE
is_null($novar) renvoie "Undefined variable error"
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
if (unset($var)){}
| 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 |