a=b , b=c et pourtant a!=c ???

Petit nouveau ! | 6 Messages

27 juil. 2011, 16:19

Bonjour !

Je viens de découvrir un comportement de PHP qui ne me parait pas vraiment logique...

Soit le code suivant:

Code : Tout sélectionner

if ($a == $b){ echo "<br>true1"; } if ($b == $c){ echo "<br>true2"; } if ($a == $c){ echo "<br>true3"; } Avec les valeurs: $a = 0; $b = 'x'; $c = true;
Je m'attend à avoir 3 true, si a = b et b = c, a devrait être égal à c... Pourtant non, la troisième condition renvoie false.
Je me suis donc rendu compte qu'un string parsé en int était égal à 0 en php, alors qu'il sera égal à true s'il est parsé en booléen... Trouvez-vous ce comportement logique ?
Voilà la fonction qui m'a amené à cette réflexion:

Code : Tout sélectionner

function mise_en_forme($mVariable){ if ($mVariable == 'now'){ return 'NOW()'; }else{ return "'$mVariable'"; }
mise_en_forme(0) renverra donc 'NOW()' ce qui n'est pas du tout le comportement attendu... (la fonction a été simplifiée, en gros c'est de la mise en forme de champ lors d'une insertion sql)

Merci pour votre commentaires et réflexions :D

ViPHP
ViPHP | 5462 Messages

27 juil. 2011, 16:23


Mammouth du PHP | 2278 Messages

27 juil. 2011, 21:00

l'exemple fonctionne.
Le vrai code doit contenir une erreur...
Et rien à vpoir avec les commentaires-fantômes sur les tables de vérité larges ou strictes...
Vanitas vanitatum et omnia vanitas
Mes derniers livres :
Sauvez les Mots chez BoD,
Tous les chemins mènent à ROM chez BoD

ViPHP
ViPHP | 5462 Messages

27 juil. 2011, 22:05

l'exemple fonctionne.
Le vrai code doit contenir une erreur...
Et rien à vpoir avec les commentaires-fantômes sur les tables de vérité larges ou strictes...
je vois que t'as rien compris au tableau ...
la tu lu au moins ?

Eléphant du PHP | 171 Messages

28 juil. 2011, 00:24

l'exemple fonctionne.
Le vrai code doit contenir une erreur...
Et rien à vpoir avec les commentaires-fantômes sur les tables de vérité larges ou strictes...
Ou pas. C'est justement directement lié... Lis le tableau !
Le bon jugement s'apprend par l'expérience qui s'acquiert en partie par le mauvais jugement.

devlop78
Invité n'ayant pas de compte PHPfrance

28 juil. 2011, 02:32

Le tableau est un bel exemple, mais comprendre serait mieux. Tu devrais donc lire la documentation sur le transtypage implicite.

On ne peut comparer que ce qui est comparable. C'est pourquoi php effectue un transtypage si nécessaire pour la comparaison de deux données de types différents (sauf pour les objets qui sont de types object quelque soit leur classe).

En gros :

'x' == 0 va devenir 0 === 0 ce qui est vrai
'x' == true va devenir true === true ce qui est vrai
0 == true va devenir false === true ce qui est faux

Tu peux utiliser l'opérateur === pour comparer sans transtypage, et alors, dès le départ, si les données sont de types différents, ils seront différents (ex : '0' === 0 renverra false)

Petit nouveau ! | 6 Messages

28 juil. 2011, 08:24

Merci pour vos réponses. Je connaissais déjà la solution, je venais simplement pour voir si j'étais le seul à être étonné, pour avoir l'avis de chacun. Mais ce tableau peut être utile.
Je trouvais illogique qu'un string converti en int soit égal à 0, alors qu'il vaudra true une fois converti en booléen. Le 0 représentait pour moi l'absence de données. Mais il est vrai que le fait d'attribuer l'int 1 à un tous les string non-numériques serrait un peu arbitraire, d'où l'obligation de mettre 0...
Alalah, php et son absence de typage :D

ViPHP
xTG
ViPHP | 7331 Messages

28 juil. 2011, 08:35

Un 0 ou un 1 pour l'absence de données ce n'est pas représentatif.
Sur certains matériels on utilise le 1 pour indiquer l'absence de données. ;)
Bref faut jamais se dire que 0 c'est false ou vide ou je ne sais quoi car au final 0 ce n'est qu'un nombre qui peut être utilisé pour tout et n'importe quoi. :mrgreen:

Eléphant du PHP | 275 Messages

28 juil. 2011, 11:11

Je trouvais illogique qu'un string converti en int soit égal à 0
Tu confond int et booléen. Le cast de 'x' en booléen ça donne bien "true" (présence de données, donc).
Par contre la conversion en int c'est différent, en php ça transforme '123' en 123, '123x' en 123, et 'x' en 0, ce qui est logique.
Mais il est vrai que le fait d'attribuer l'int 1 à un tous les string non-numériques serrait un peu arbitraire, d'où l'obligation de mettre 0...
D'ou la version booléenne
Alalah, php et son absence de typage :D
Ben, justement, il y a des types de données, la preuve. Tu sais pas t'en servir, c'est différent.

Petit nouveau ! | 6 Messages

28 juil. 2011, 11:35

Alalah, php et son absence de typage :D
Ben, justement, il y a des types de données, la preuve. Tu sais pas t'en servir, c'est différent.[/quote]

Je voulais parler de l'absence de typage des variables lors de la déclaration. Dans la plupart des langages on défini le type à la déclaration et on s'y tient jusqu'au bout. Php gère le typage des variables, mais est tellement permissif qu'on ne s'en sert quasiment jamais (sachant en plus qu'il faudrait rajouter une ligne settype pour chaque variable).
Mais on est bien d'accord, j'ai mélangé les types dans ma condition et je ne peut m'en prendre qu'à moi si je n'ai pas le résultat attendu.
Même si j'avais déjà réglé le problème, je trouvais le comportement illogique. J'ai maintenant compris la raison, c'est ce que je voulais.

Eléphant du PHP | 275 Messages

28 juil. 2011, 11:47

Dans la plupart des langages on défini le type à la déclaration et on s'y tient jusqu'au bout.
En php, rien ne nous y oblige. Ni a indenter, ni a commenter. C'est a chacun de s'imposer d'y faire attention, perso, je déclare mes variables, et elles ont un type quasi fixe.
Php gère le typage des variables, mais est tellement permissif qu'on ne s'en sert quasiment jamais (sachant en plus qu'il faudrait rajouter une ligne settype pour chaque variable).
Idem, libre a chacun de s'en servir. Et nul besoin de settype : $a = 0; suffit a dire que $a est un int. Tu veux récupérer une valeur dont tu n'est pas sur du type ? $a = intval($_GET['a']);

Ce genre de rigueur évite bien des problèmes, et transforme la "galère du typage php" en une feature sympathique qu'on peut utiliser.

Mammouth du PHP | 2278 Messages

28 juil. 2011, 22:49

surement pas. Le typage explicite et obligatoire et l'initialisation de toutes les variables sont de toute évidence un énorme avantage. Et ça éciterait ce genre de débat. Avec des variables typées on n'aurait pas besoin de === et == et ainsi soit-il.
Vanitas vanitatum et omnia vanitas
Mes derniers livres :
Sauvez les Mots chez BoD,
Tous les chemins mènent à ROM chez BoD

Eléphant du PHP | 171 Messages

28 juil. 2011, 23:54

surement pas. Le typage explicite et obligatoire et l'initialisation de toutes les variables sont de toute évidence un énorme avantage. Et ça éciterait ce genre de débat. Avec des variables typées on n'aurait pas besoin de === et == et ainsi soit-il.
J'aime bien le typage de PHP, je trouve qu'il est d'une certaine souplesse. De plus l'opérateur === n'est pas super contraignant. C'est même plutôt simple à gérer je dirais. Comme son nom l'indique comparaison stricte, si on cherche une valeur précise ou l'inverse dans l'autre cas.
Le bon jugement s'apprend par l'expérience qui s'acquiert en partie par le mauvais jugement.

devlop78
Invité n'ayant pas de compte PHPfrance

29 juil. 2011, 02:32

Je rebondis sur la réponse : un string n'est pas converti en 0. D'après mes connaissances, les langages respectent globalement la même logique en transtypage, et le transtypage est permis partout. La différence de trouve au niveau du typage, s'il est fort ou non.

Par exemple, un langage fortement typé te proposera de caster (transtyper) un String vers un Integer. par exemple : int x = (int) str_nombre

Le but étant d'avoir un résultat logique, mettre 0 arbitrairement ne répondrait pas aux problématique (on ne transtype pas pour le plaisir). Si un utilisateur tape "53" dans un formulaire, le résultat côté serveur sera toujours un String. Il faut donc le transtyper pour agir dessus, et la régle générale que les langages ont choisie c'est de convertir tout ce qui se trouve avant une première lettre (en gros). Donc "53" deviendra 53, "85x" deviendra 85 et "abdel" deviendra 0.

Ce qui est drôle c'est que tu te défends sur ta propre question en donnant comme exemple du typage fort alors que leur réaction est similaire si ce n'est identique (mais mon expérience ne me permet pas d'affirmer qu'ils le sont).

Petit nouveau ! | 6 Messages

29 juil. 2011, 08:17

Je rebondis sur la réponse : un string n'est pas converti en 0. D'après mes connaissances, les langages respectent globalement la même logique en transtypage, et le transtypage est permis partout. La différence de trouve au niveau du typage, s'il est fort ou non.

Par exemple, un langage fortement typé te proposera de caster (transtyper) un String vers un Integer. par exemple : int x = (int) str_nombre

Le but étant d'avoir un résultat logique, mettre 0 arbitrairement ne répondrait pas aux problématique (on ne transtype pas pour le plaisir). Si un utilisateur tape "53" dans un formulaire, le résultat côté serveur sera toujours un String. Il faut donc le transtyper pour agir dessus, et la régle générale que les langages ont choisie c'est de convertir tout ce qui se trouve avant une première lettre (en gros). Donc "53" deviendra 53, "85x" deviendra 85 et "abdel" deviendra 0.

Ce qui est drôle c'est que tu te défends sur ta propre question en donnant comme exemple du typage fort alors que leur réaction est similaire si ce n'est identique (mais mon expérience ne me permet pas d'affirmer qu'ils le sont).
Effectivement pour le transtypage des ints il est identique aux autres languages (encore heureux !) donc '1' vaudra 1, '1x' vaudra 1 et 'x' vaudra 0.
Et effectivement le comportement de php sera identique à un typage fort, si ce n'est que le type choisi lors d'une comparaison souple (==) de deux variables de types différents sera implicite: le type le plus restrictif (si je ne fais pas d'erreur).
- lors de la comparaison d'un string à un int, php castera le string en int
- lors de la comparaison d'un string à un booléen, php castera le string en booléen
Dans ma fonction donnée en exemple, j'aurais par exemple dû convertir manuellement ma variable de type mixed en string pour la comparaison, pour éviter que la présence d'un int force le cast du 'NOW()' en int, soit 0.