Gilliek
12nov/100

PHP : Une erreur d’operateur

En PHP, on peut affecter une valeur à une variable  selon une certaine condition avec des opérateurs ternaires.

Par exemple :

On aimerait que la variable result vaille 42 si x est plus grand que y et 0 sinon. Sans les opérateurs ternaires ça donnerait ça :

if (x > y)
     result = 42;
else
     result = 0;

ça prend 4 lignes et c'est moche ! C'est là que les opérateurs ternaires interviennent. On peut réécrire avec ceux-ci le code ci-dessus de la manière suivante :

result = (x > y) ? 42 : 0;

Beaucoup plus beau, non ?

Si tout fonctionnait pour le mieux dans le meilleur des monde (dédicace à Candide de Voltaire) je n'en parlerai sans doute pas dans ce billet !

A vos consoles !

Plutôt qu'un long et interminable discours, un exemple ! Comme le laisse suggérer le titre, ouvrez une console (ou terminal) ;-)

Maintenant, exécutez-y la commande suivante (il faut avoir au préalable installé PHP) :

php -r 'print 42 > 100 ? "42 est plus grand que 100" : 42 < 100 ? "42 est plus petit que 100" : "42 est égal à 100";'

Ca marche ...

Si vous avez bien recopié la commande, vous devriez voir s'afficher :

42 est plus petit que 100

... mais pas toujours !

Maintenant, inversons l'ordre des opérations ! Saisissez donc la commande :

php -r 'print 42 < 100 ? "42 est plus petit que 100" : 42 > 100 ? "42 est plus grand que 100" : "42 est égal à 100";'

Et là vous voyer s'afficher un terrible résultat :

42 est plus grand que 100

Comme vous pouvez le constater, le résultat est faux : 42 n'est pas plus grand que 100 :-P

Je sais bien que 42 est la réponse universelle, mais faut pas abuser non plus !

Mais pourquoi ?

Il s'agit en fait d'un problème d'associativité des opérateur '?' et ':' dans PHP.  En effet, en PHP, ces deux opérateurs sont left-associative (associatif à gauche pour les non-anglophones). Et c'est le seul langage à contenir une telle abération.

Prenons Ruby (il vous faut avoir installé Ruby pour pouvoir lancer la commande, évidemment):

ruby -e 'print 42 < 100 ? "42 est plus petit que 100" : 42 > 100 ? "42 est plus grand que 100" : "42 est égal à 100"'

L'interpréteur Ruby nous sort :

42 est plus petit que 100

Que faire ?

Il y a deux solutions:

  1. A court terme : utiliser des parenthèses pour bien définir l'ordre des opérations.
  2. A long terme : Ne plus utiliser PHP :-P Bon, je sais, c'est un peu radical et parfois on n'a pas vraiment le choix :-D

Si vous voulez d'autres exemples d'absurdités de PHP, je vous recommande le site (en anglais) : http://www.steike.com/code/php-must-die/