Article complet: Transtypage et comparaison en PHP

19/09/2007

Permalink 21:22:28, Catégories: php, Récapitulatif Web, 899 mots   French (FR) , julien pauli

[Web] Transtypage et comparaison en PHP

C'est un sujet largement abordé lors du passage de la certification, il n'est pas complexe, mais il y a des notions qu'il faut maitriser.
PHP est faiblement typé. Sans répéter la documentation officielle, je vais rester concis et peut-être en faire gamberger certains, je vais faire un point général sur les règles de transtypage(appelé aussi 'cast') en PHP, et sur les comparaisons.

l'opérateur == compare 2 entités, pour cela il faut qu'elles soient du même type, et c'est bien là qu'une tonne d'astuces est à mémoriser.
Je parlerais après de l'opérateur d'identité ===

  • Si je compare une chaine à un nombre, la chaine est implicitement castée en nombre
  • Si je compare 2 chaines représentants des nombres, elles sont implicitement castées comme des nombres
  • Un nombre est un entier, si il n'a pas de partie décimale, un nombre peut donc être un entier, ou un décimal (contenant donc un . ou un e, pour exposant)
  • Si je compare un booléen ou la valeur NULL à n'importe quoi, le cast se fait vers le booléen
  • Si je compare un tableau à une chaine ou un nombre, le tableau est toujours supérieur, il n'y a pas de cast implicite
  • Si je compare un objet à une chaine ou un nombre, l'objet est systématiquement supérieur, il n'y a pas de cast implicite
  • L'objet est supérieur au tableau, quels qu'ils soient.

Le cast fonctionne comme ceci :
null, 0, '0' et "" valent false
false est casté en '' pour la chaine, et 0 pour l'entier
un objet vaut toujours true (PHP5)
un array vaut true s'il est non vide
un array vaut l'entier 1, s'il est non vide, 0 sinon
un objet donne une erreur en le castant en string, s'il n'a pas de méthode __tostring()
un objet vers un entier passe par la string
la chaine si elle commence par un nombre, vaut ce nombre
la chaine si elle représente un nombre flottant, vaut la partie entière de ce nombre, lors du cast en entier (il n'y a pas d'arrondi!)

Il est très intéréssant de noter ceci :

 
000e0024785073 == "0e22541f857" // true : le chaine est convertie en nombre, et 0 == 0
"000e0024785073" == "0e22541f857" // false : la chaine de droite ne représente pas la syntaxe correcte d'un nombre, PHP compare donc 2 strings ici
"000e0024785073" == "00f225418578" // false : idem
array('2') == 2 // false 
'2' == 2 // true 
10 == "10.0" // true 
10 == "10.0e00" // true 
10 == "10.0e001" // false 
new StdClass == array() // false 
$a = new StdClass; $a->a = 1; $a == array('a'=>1); // false 
false == array(0); // false 
 
(int)array(2) == 2 // false 
 
(int)array(null) == 0 // false 
(int)array() == 0 // true 
 
array(3) == 8 // false

Regardez cette "contre logique", mais qui suit bien les règles énoncées plus haut :

array() == 0 // false : un tableau est supérieur à un entier 
array() == null // true : un tableau vide vaut false, null vaut false , et false == false 
null == 0 // true : null vaut false, 0 vaut false 
null == '' // true : idem 
 
array(1) == true // true, le tableau est converti vers un le booléen, il est non vide, il vaut donc true 
new StdClass == true // true, l'objet est converti en booléen, et un objet vide vaut true en PHP5, pas en PHP4 
(array)true == 1 // false, true est converti en array, et un array face à un entier est toujours supérieur 
(int)(array)2 == 2 // false, l'entier 2 est converti en array, mais un array convertit en entier vaut toujours 1, sauf s'il est vide, or 1 n'est pas égal à 2

Regardez encore :

array(3,4,null) == 1 // false : un array est supérieur à un entier 
(int)array(3,4,null) == 1 // true : un array vaut 1 lorsque non vide, et 1 == 1

Continuons un peu :

new StdClass == array() // false : un objet est supérieur à un array 
 
new StdClass > "2" // true : l'objet est supérieur à l'entier 
(string)new StdClass > "2" // error : stdClass n'a pas de méthode __tostring() déclarée (implicitement). 
array() > 0 //true : idem 
new stdClass > null // true : Ici la conversion se fait en booléen, un objet vaut true, et null vaut false, true est supérieur à false.

La certification ne donne pas de cas très complexes, en général, c'est un string contre un entier, et éventuellement la string contient un 'E', ou alors l'entier commence par 0 (octal)...
Néanmoins, nous venons de voit qu'il y a des subtilités qu'il faut connaitre, et nous n'avons parlé que de l'opérateur de comparaison, double égal, et pas des opérateurs de bits (&), ou booléens (&&)...

Un petit mot sur l'identité ===
2 opérandes sont identiques (===), s'ils sont égaux en valeur ET en type. Il n'y a pas trop de gotcha! au niveau des strings ou des nombres, en revanche il faut mémoriser pour les objets et les tableaux, que :

  • 2 objets sont identiques s'ils pointent vers la même instance
  • 2 tableaux sont identiques s'ils contiennent les mêmes paires clés/valeurs dans le même ordre et du même type

array('a','b','2') === array('a','b',2) // false car '2' n'est pas identique à 2.
array(0=>'a',1=>'b') === array(1=>'b',0=>'a') // false, les valeurs n'ont pas été insérées dans le même ordre
array('0'=>'a',1=>'b') === array(0=>'a','1'=>'b') // true, les clés string représentant des numériques sont converties implicitement en numérique
new stdClass === new stdClass // false, il ne s'agit pas de la même instance

Social Bookmarking:

                                     

Commentaires:

Connectez-vous pour vous abonner à cet article:

Flux de commentaires pour cet article : Atom 1.0  RSS 2.0
Commentaire de: pyrou [Membre]
Bonjour,

petite précision

"Si je compare un objet à une chaine ou un nombre, l'objet est systématiquement supérieur"

Il semble que l'objet soit casté en 1 en cas de comparaison avec un nombre

Class Classe {}
echo (new Classe() > 5)? "true":"false"; // affiche false
Permalien 05/10/2007 @ 19:48
Commentaire de: julien pauli [Membre] · http://www.anaska.com
Oui j'ai fait une petite erreur, cependant :

Notice: Object of class Classe could not be converted to int in PHPDocument1 on line 4

PHP retourne 1, oui, mais génère une erreur. On retiendra donc qu'un objet ne peut être converti (proprement) vers un entier.

echo (int)new Stdclass;
Affiche effectivement 1, mais avec une erreur, il faut donc bannir ce transtypage et donc, ce type de comparaison.
Permalien 05/10/2007 @ 21:33

Vous devez être identifié pour poster un commentaire.

Liste des blogs

Julien Pauli DevPHP blog

Developpement web PHP

Rechercher

<  Février 2010  >
Lun Mar Mer Jeu Ven Sam Dim
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28

Syndiquez ce blog XML

Articles :

Commentaires :

Vos questions techniques : forum d'entraide Blogs - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Hébergement - Participez - Copyright © 2000-2010 www.developpez.com - Legal informations.