web-dev-qa-db-fra.com

Jonglage de type et comparaisons (strictes) supérieures / inférieures à PHP

PHP est célèbre pour sa jonglerie de types. Je dois admettre que cela me laisse perplexe, et j'ai du mal à trouver des choses logiques/fondamentales de base dans les comparaisons.

Par exemple: Si $a > $b est vrai et $b > $c est vrai, doit-il signifier que $a > $c est toujours vrai aussi?

Suivant la logique de base, je dirais oui mais je suis si perplexe que je ne fais pas vraiment confiance à PHP dans ce domaine). Peut-être que quelqu'un peut donner un exemple où ce n'est pas le cas?

Je me demande également avec les opérateurs strictement inférieurs à et strictement supérieurs à (car leur signification est décrite comme strictement que je ne connaissais dans le passé que par les comparaisons d'égalité) si cela fait une différence si les opérandes gauche et droite sont échangés avec valeurs strictement inégales:

# Precondition:
if ($a === $b) {
    throw new Exception(
       'Both are strictly equal - can not compare strictly for greater or smaller'
    );
}

($a > $b) !== ($b > $a)

Pour la plupart des combinaisons de comparaison de types, ces opérateurs de comparaison plus/moins ne sont pas documentés, donc la lecture du manuel n'a pas été vraiment utile dans ce cas.

113
hakre

Les opérateurs de comparaison de PHP s'écartent des définitions informatiques de plusieurs manières:

Pour constituer une relation d'équivalence== Doit être réflexif, symétrique et transitif:

  • L'opérateur == De PHP n'est pas non réflexif , c'est-à-dire que $a == $a N'est pas toujours vrai:

    var_dump(NAN == NAN); // bool(false)
    

    Remarque: Le fait que toute comparaison impliquant NAN est toujours false n'est pas spécifique à PHP. Il est mandaté par la norme IEEE 754 pour l'arithmétique en virgule flottante ( plus d'informations ).

  • L'opérateur == De PHP est symétrique , c'est-à-dire que $a == $b Et $b == $a Sont toujours les mêmes.

  • L'opérateur == De PHP n'est pas transitif , c'est-à-dire de $a == $b Et $b == $c Le fait pas suit $a == $c:

    var_dump(true == "a"); // bool(true)
    var_dump("a" == 0);    // bool(true)
    var_dump(true == 0);   // bool(false)
    

Pour constituer un ordre partiel<=/>= Doit être réflexif, anti-symétrique et transitif:

  • L'opérateur <= De PHP n'est pas non réflexif , c'est-à-dire que $a <= $a N'est pas toujours vrai (Exemple identique à ==).

  • L'opérateur <= De PHP n'est pas anti-symétrique , c'est-à-dire de $a <= $b Et $b <= $a Ne suit pas $a == $b:

    var_dump(NAN <= "foo"); // bool(true)
    var_dump("foo" <= NAN); // bool(true)
    var_dump(NAN == "foo"); // bool(false)
    
  • L'opérateur <= De PHP n'est pas transitif , c'est-à-dire de $a <= $b Et $b <= $c Ne suit pas $a <= $c (Exemple identique à ==).

  • Extra: l'opérateur <= De PHP n'est pas pas total , c'est-à-dire que $a <= $b Et $b <= $a Peuvent être faux :

    var_dump(new stdClass <= new DateTime); // bool(false)
    var_dump(new DateTime <= new stdClass); // bool(false)
    

Pour constituer un ordre partiel strict</> Doit être irréflexif, asymétrique et transitif:

  • L'opérateur < De PHP est irréflexif , c'est-à-dire que $a < $a N'est jamais vrai. Notez que cela n'est vrai qu'à partir de PHP 5.4 . Auparavant, INF < INF Était évalué à true.

  • L'opérateur < De PHP n'est pas asymétrique , c'est-à-dire que de $a < $b Ne suit pas !($b < $a) (Exemple identique à <= n'étant pas anti-symétrique).

  • L'opérateur < De PHP n'est pas transitif , c'est-à-dire de $a < $b Et $b < $c Ne suit pas $a < $c:

    var_dump(-INF < 0);    // bool(true)
    var_dump(0 < TRUE);    // bool(true)
    var_dump(-INF < TRUE); // bool(false)
    
  • Extra: l'opérateur < De PHP n'est pas pas trichotomique , c'est-à-dire tous $a < $b, $b < $a Et $a == $b Peut être faux (exemple identique à <= N'étant pas total).

  • Extra: l'opérateur < De PHP peut être circulaire , c'est-à-dire qu'il est possible que $a < $b, $b < $c et $c < $a:

    var_dump(INF < []);           // bool(true)
    var_dump([] < new stdClass);  // bool(true)
    var_dump(new stdClass < INF); // bool(true)
    

    Remarque: L'exemple ci-dessus renvoie un avis "L'objet de la classe stdClass n'a pas pu être converti en double".

Vous pouvez trouver quelques bons graphiques pour les opérateurs de comparaison de PHP sur PHP Sadness 52 - Opérateurs de comparaison .

Enfin, je tiens à souligner qu'il existe deux égalités que PHP le fait garantie (contrairement à presque tout le reste). Ces deux sont toujours valables, simplement parce que le compilateur se réduit l'un à l'autre:

($a > $b) == ($b < $a)
($a >= $b) == ($b <= $a)
204
NikiC

Après avoir corrigé la deuxième partie de votre question, je laisse la réponse à cette partie aux autres. Je veux juste donner la réponse la plus surprenante à la première partie de votre question, à savoir s'il existe un exemple des opérateurs < Et > Intransitifs. C'est ici.

Ce sont tous true:

"10" < "1a"
"1a" < "2"
"10" > "2"

Si < Était transitif ($a < $b$b < $c$a < $c), La dernière ligne serait

"10" < "2"

mais PHP essaie d'être gentil (?!) et interprète les chaînes comme des nombres chaque fois qu'il le peut.

Il s'avère qu'en raison de l'intransitivité ci-dessus, sort() peut trier les mêmes éléments en un ordre différent en fonction de leur ordre d'entrée, même lorsque deux éléments ne sont pas == ( et aucun élément n'est NAN). Je l'ai souligné dans un commentaire pour trier () , dont l'essence est:

sort(array("10", "1a", "2" )) => array("10", "1a", "2" )
sort(array("10", "2",  "1a")) => array("1a", "2",  "10")
sort(array("1a", "10", "2" )) => array("2",  "10", "1a")
sort(array("1a", "2",  "10")) => array("1a", "2",  "10")
sort(array("2",  "10", "1a")) => array("2",  "10", "1a")
sort(array("2",  "1a", "10")) => array("10", "1a", "2" )
22
Walter Tross