Type-juggling and (strict) greater/lesser-than comparisons in PHP

后端 未结 3 1011
执念已碎
执念已碎 2020-11-28 17:45

PHP is famous for its type-juggling. I must admit it puzzles me, and I\'m having a hard time to find out basic logical/fundamental things in comparisons.

For example

相关标签:
3条回答
  • 2020-11-28 18:12

    There are no strict identical comparison operators (>== or <==) in PHP (by PHP 5.6.14 at least), but there are a few ways to enforce a strict type check before checking Greater/Lower:

    1. Check both variable types with if (gettype($a) === gettype($b))
    2. Force your needed type-cast eg. if ((string)$a === (string)$b)
    3. Force your needed type-juggle eg. if (($a . '') === ($b . ''))

    Take note that:

    • Floating point precision is limited
    • INF and NAN are of type float under ieee754
    • Some Infinity equals some other Infinity (since PHP 5.4)
    • Scientific notation e is always of type float, and never integer even if the number is small
    • Integers going over PHP_INT_MAX get automatically converted to float
    • Floats over system's boundaries get the INF value
    • Undefined variables are of type and value NULL
    • Integers preceded by 0 are converted from octal to decimal (by convention)
    • Converting Strings containing an integer with a leading 0 to integer strips the leading 0

    List of some exotic comparisons:

    Very strange:
         $a      VS.     $b         $a>$b   $a<$b   $a<=$b  $a>=$b  $a==$b  $a===$b
      float(NAN)    float(-INF)     false   false   false   false   false   false
      float(NAN)      float(0)      false   false   false   false   false   false
      float(NAN)      float(1)      false   false   false   false   false   false
      float(NAN)     float(INF)     false   false   false   false   false   false
      float(NAN)     float(NAN)     false   false   false   false   false   false
      float(NAN)      int(-1)       false   false   false   false   false   false
      float(NAN)       int(0)       false   false   false   false   false   false
      float(NAN)       int(1)       false   false   false   false   false   false
    

    Equal but not identical:

         $a      VS.     $b         $a>$b   $a<$b   $a<=$b  $a>=$b  $a==$b  $a===$b
    
      NULL(NULL)      array()       false   false    true    true    true   false
      NULL(NULL)    bool(false)     false   false    true    true    true   false
      NULL(NULL)      float(0)      false   false    true    true    true   false
      NULL(NULL)       int(0)       false   false    true    true    true   false
      NULL(NULL)      str('')       false   false    true    true    true   false
       array()      bool(false)     false   false    true    true    true   false
     bool(false)      float(0)      false   false    true    true    true   false
     bool(false)       int(0)       false   false    true    true    true   false
       str('')      bool(false)     false   false    true    true    true   false
     bool(false)      str('0')      false   false    true    true    true   false
     float(-INF)     bool(true)     false   false    true    true    true   false
      bool(true)      float(1)      false   false    true    true    true   false
      float(INF)     bool(true)     false   false    true    true    true   false
      float(NAN)     bool(true)     false   false    true    true    true   false
      bool(true)      int(-1)       false   false    true    true    true   false
      bool(true)       int(1)       false   false    true    true    true   false
      bool(true)     str("\0")      false   false    true    true    true   false
      bool(true)      str('+')      false   false    true    true    true   false
      bool(true)      str('-')      false   false    true    true    true   false
      bool(true)     str('01')      false   false    true    true    true   false
      bool(true)      str('1')      false   false    true    true    true   false
      bool(true)    str('false')    false   false    true    true    true   false
     str('text')     bool(true)     false   false    true    true    true   false
     str('true')     bool(true)     false   false    true    true    true   false
        int(0)        float(0)      false   false    true    true    true   false
      str("\0")       float(0)      false   false    true    true    true   false
       str('')        float(0)      false   false    true    true    true   false
       str('+')       float(0)      false   false    true    true    true   false
       str('-')       float(0)      false   false    true    true    true   false
       str('0')       float(0)      false   false    true    true    true   false
     str('false')     float(0)      false   false    true    true    true   false
     str('text')      float(0)      false   false    true    true    true   false
     str('true')      float(0)      false   false    true    true    true   false
        int(1)        float(1)      false   false    true    true    true   false
       float(1)      str('01')      false   false    true    true    true   false
       float(1)       str('1')      false   false    true    true    true   false
      str("\0")        int(0)       false   false    true    true    true   false
       str('')         int(0)       false   false    true    true    true   false
       str('+')        int(0)       false   false    true    true    true   false
       str('-')        int(0)       false   false    true    true    true   false
        int(0)        str('0')      false   false    true    true    true   false
     str('false')      int(0)       false   false    true    true    true   false
     str('text')       int(0)       false   false    true    true    true   false
     str('true')       int(0)       false   false    true    true    true   false
        int(1)       str('01')      false   false    true    true    true   false
        int(1)        str('1')      false   false    true    true    true   false
       str('1')      str('01')      false   false    true    true    true   false
    

    Lower and Greater at the same time?

         $a      VS.     $b         $a>$b   $a<$b   $a<=$b  $a>=$b  $a==$b  $a===$b
      float(NAN)     str("\0")       true    true    true    true   false   false
      float(NAN)      str('')        true    true    true    true   false   false
      float(NAN)      str('+')       true    true    true    true   false   false
      float(NAN)      str('-')       true    true    true    true   false   false
      float(NAN)      str('0')       true    true    true    true   false   false
      float(NAN)     str('01')       true    true    true    true   false   false
      float(NAN)      str('1')       true    true    true    true   false   false
      float(NAN)    str('false')     true    true    true    true   false   false
      float(NAN)    str('text')      true    true    true    true   false   false
      float(NAN)    str('true')      true    true    true    true   false   false
    

    Equal AND identical:

         $a      VS.     $b         $a>$b   $a<$b   $a<=$b  $a>=$b  $a==$b  $a===$b
      NULL(NULL)     NULL(NULL)     false   false    true    true    true    true
     float(-INF)    float(-INF)     false   false    true    true    true    true
      float(INF)     float(INF)     false   false    true    true    true    true
    

    Lower or Greater:

         $a      VS.     $b         $a>$b   $a<$b   $a<=$b  $a>=$b  $a==$b  $a===$b
    
      NULL(NULL)     bool(true)     false    true    true   false   false   false
     float(-INF)     NULL(NULL)      true   false   false    true   false   false
      NULL(NULL)      float(1)      false    true    true   false   false   false
      float(INF)     NULL(NULL)      true   false   false    true   false   false
      float(NAN)     NULL(NULL)      true   false   false    true   false   false
      NULL(NULL)      int(-1)       false    true    true   false   false   false
      NULL(NULL)       int(1)       false    true    true   false   false   false
      NULL(NULL)     str("\0")      false    true    true   false   false   false
      NULL(NULL)      str('+')      false    true    true   false   false   false
      NULL(NULL)      str('-')      false    true    true   false   false   false
      NULL(NULL)      str('0')      false    true    true   false   false   false
      NULL(NULL)     str('01')      false    true    true   false   false   false
      NULL(NULL)      str('1')      false    true    true   false   false   false
      NULL(NULL)    str('false')    false    true    true   false   false   false
      NULL(NULL)    str('text')     false    true    true   false   false   false
      NULL(NULL)    str('true')     false    true    true   false   false   false
       array()       bool(true)     false    true    true   false   false   false
     float(-INF)      array()       false    true    true   false   false   false
       array()        float(0)       true   false   false    true   false   false
       array()        float(1)       true   false   false    true   false   false
      float(INF)      array()       false    true    true   false   false   false
      float(NAN)      array()       false    true    true   false   false   false
       array()        int(-1)        true   false   false    true   false   false
       array()         int(0)        true   false   false    true   false   false
       array()         int(1)        true   false   false    true   false   false
       array()       str("\0")       true   false   false    true   false   false
       str('')        array()       false    true    true   false   false   false
       array()        str('+')       true   false   false    true   false   false
       array()        str('-')       true   false   false    true   false   false
       array()        str('0')       true   false   false    true   false   false
       array()       str('01')       true   false   false    true   false   false
       array()        str('1')       true   false   false    true   false   false
       array()      str('false')     true   false   false    true   false   false
       array()      str('text')      true   false   false    true   false   false
       array()      str('true')      true   false   false    true   false   false
      bool(true)    bool(false)      true   false   false    true   false   false
     float(-INF)    bool(false)      true   false   false    true   false   false
       float(1)     bool(false)      true   false   false    true   false   false
      float(INF)    bool(false)      true   false   false    true   false   false
      float(NAN)    bool(false)      true   false   false    true   false   false
     bool(false)      int(-1)       false    true    true   false   false   false
        int(1)      bool(false)      true   false   false    true   false   false
     bool(false)     str("\0")      false    true    true   false   false   false
     bool(false)      str('+')      false    true    true   false   false   false
     bool(false)      str('-')      false    true    true   false   false   false
     bool(false)     str('01')      false    true    true   false   false   false
       str('1')     bool(false)      true   false   false    true   false   false
     bool(false)    str('false')    false    true    true   false   false   false
     str('text')    bool(false)      true   false   false    true   false   false
     str('true')    bool(false)      true   false   false    true   false   false
      bool(true)      float(0)       true   false   false    true   false   false
      bool(true)       int(0)        true   false   false    true   false   false
       str('')       bool(true)     false    true    true   false   false   false
      bool(true)      str('0')       true   false   false    true   false   false
     float(-INF)      float(0)      false    true    true   false   false   false
     float(-INF)      float(1)      false    true    true   false   false   false
      float(INF)    float(-INF)      true   false   false    true   false   false
     float(-INF)      int(-1)       false    true    true   false   false   false
     float(-INF)       int(0)       false    true    true   false   false   false
     float(-INF)       int(1)       false    true    true   false   false   false
     float(-INF)     str("\0")      false    true    true   false   false   false
     float(-INF)      str('')       false    true    true   false   false   false
     float(-INF)      str('+')      false    true    true   false   false   false
     float(-INF)      str('-')      false    true    true   false   false   false
     float(-INF)      str('0')      false    true    true   false   false   false
     float(-INF)     str('01')      false    true    true   false   false   false
     float(-INF)      str('1')      false    true    true   false   false   false
     float(-INF)    str('false')    false    true    true   false   false   false
     float(-INF)    str('text')     false    true    true   false   false   false
     float(-INF)    str('true')     false    true    true   false   false   false
       float(1)       float(0)       true   false   false    true   false   false
      float(INF)      float(0)       true   false   false    true   false   false
       float(0)       int(-1)        true   false   false    true   false   false
        int(1)        float(0)       true   false   false    true   false   false
       float(0)      str('01')      false    true    true   false   false   false
       str('1')       float(0)       true   false   false    true   false   false
      float(INF)      float(1)       true   false   false    true   false   false
       float(1)       int(-1)        true   false   false    true   false   false
       float(1)        int(0)        true   false   false    true   false   false
       float(1)      str("\0")       true   false   false    true   false   false
       str('')        float(1)      false    true    true   false   false   false
       float(1)       str('+')       true   false   false    true   false   false
       float(1)       str('-')       true   false   false    true   false   false
       float(1)       str('0')       true   false   false    true   false   false
       float(1)     str('false')     true   false   false    true   false   false
     str('text')      float(1)      false    true    true   false   false   false
     str('true')      float(1)      false    true    true   false   false   false
      float(INF)      int(-1)        true   false   false    true   false   false
      float(INF)       int(0)        true   false   false    true   false   false
      float(INF)       int(1)        true   false   false    true   false   false
      float(INF)     str("\0")       true   false   false    true   false   false
      float(INF)      str('')        true   false   false    true   false   false
      float(INF)      str('+')       true   false   false    true   false   false
      float(INF)      str('-')       true   false   false    true   false   false
      float(INF)      str('0')       true   false   false    true   false   false
      float(INF)     str('01')       true   false   false    true   false   false
      float(INF)      str('1')       true   false   false    true   false   false
      float(INF)    str('false')     true   false   false    true   false   false
      float(INF)    str('text')      true   false   false    true   false   false
      float(INF)    str('true')      true   false   false    true   false   false
        int(0)        int(-1)        true   false   false    true   false   false
        int(1)        int(-1)        true   false   false    true   false   false
      str("\0")       int(-1)        true   false   false    true   false   false
       str('')        int(-1)        true   false   false    true   false   false
       str('+')       int(-1)        true   false   false    true   false   false
       str('-')       int(-1)        true   false   false    true   false   false
       str('0')       int(-1)        true   false   false    true   false   false
       int(-1)       str('01')      false    true    true   false   false   false
       str('1')       int(-1)        true   false   false    true   false   false
     str('false')     int(-1)        true   false   false    true   false   false
     str('text')      int(-1)        true   false   false    true   false   false
     str('true')      int(-1)        true   false   false    true   false   false
        int(1)         int(0)        true   false   false    true   false   false
        int(0)       str('01')      false    true    true   false   false   false
       str('1')        int(0)        true   false   false    true   false   false
        int(1)       str("\0")       true   false   false    true   false   false
       str('')         int(1)       false    true    true   false   false   false
        int(1)        str('+')       true   false   false    true   false   false
        int(1)        str('-')       true   false   false    true   false   false
        int(1)        str('0')       true   false   false    true   false   false
        int(1)      str('false')     true   false   false    true   false   false
     str('text')       int(1)       false    true    true   false   false   false
     str('true')       int(1)       false    true    true   false   false   false
       str('')       str("\0")      false    true    true   false   false   false
       str('+')      str("\0")       true   false   false    true   false   false
       str('-')      str("\0")       true   false   false    true   false   false
      str("\0")       str('0')      false    true    true   false   false   false
      str("\0")      str('01')      false    true    true   false   false   false
       str('1')      str("\0")       true   false   false    true   false   false
     str('false')    str("\0")       true   false   false    true   false   false
     str('text')     str("\0")       true   false   false    true   false   false
     str('true')     str("\0")       true   false   false    true   false   false
       str('')        str('+')      false    true    true   false   false   false
       str('')        str('-')      false    true    true   false   false   false
       str('')        str('0')      false    true    true   false   false   false
       str('')       str('01')      false    true    true   false   false   false
       str('')        str('1')      false    true    true   false   false   false
       str('')      str('false')    false    true    true   false   false   false
       str('')      str('text')     false    true    true   false   false   false
       str('')      str('true')     false    true    true   false   false   false
       str('-')       str('+')       true   false   false    true   false   false
       str('+')       str('0')      false    true    true   false   false   false
       str('+')      str('01')      false    true    true   false   false   false
       str('1')       str('+')       true   false   false    true   false   false
     str('false')     str('+')       true   false   false    true   false   false
     str('text')      str('+')       true   false   false    true   false   false
     str('true')      str('+')       true   false   false    true   false   false
       str('-')       str('0')      false    true    true   false   false   false
       str('-')      str('01')      false    true    true   false   false   false
       str('1')       str('-')       true   false   false    true   false   false
     str('false')     str('-')       true   false   false    true   false   false
     str('text')      str('-')       true   false   false    true   false   false
     str('true')      str('-')       true   false   false    true   false   false
       str('0')      str('01')      false    true    true   false   false   false
       str('1')       str('0')       true   false   false    true   false   false
     str('false')     str('0')       true   false   false    true   false   false
     str('text')      str('0')       true   false   false    true   false   false
     str('true')      str('0')       true   false   false    true   false   false
     str('false')    str('01')       true   false   false    true   false   false
     str('text')     str('01')       true   false   false    true   false   false
     str('true')     str('01')       true   false   false    true   false   false
       str('1')     str('false')    false    true    true   false   false   false
     str('text')      str('1')       true   false   false    true   false   false
     str('true')      str('1')       true   false   false    true   false   false
     str('text')    str('false')     true   false   false    true   false   false
     str('true')    str('false')     true   false   false    true   false   false
     str('true')    str('text')      true   false   false    true   false   false
    

    $a > $b > $c Conundrum when: $a is not greater than $c.

    A<C   : float(NAN)  >  str('a')   >   str('')
    A<C   : float(NAN)  >  str('a')   >   str('1')
    A<C   : float(NAN)  >  str('a')   >   str('A')
    A<C   : float(NAN)  >  str('a')   >   str('0')
    A<C   : float(NAN)  >  str('1')   >   str('')
    A<C   : float(NAN)  >  str('1')   >   str('0')
    A<C   : float(NAN)  >  str('A')   >   str('')
    A<C   : float(NAN)  >  str('A')   >   str('1')
    A<C   : float(NAN)  >  str('A')   >   str('0')
    A<C   : float(NAN)  >  str('0')   >   str('')
    A<C   :   str('')   > float(NAN)  >   str('a')
    A<C   :   str('')   > float(NAN)  >   str('1')
    A<C   :   str('')   > float(NAN)  >   str('A')
    A<C   :   str('')   > float(NAN)  >   str('0')
    A<C   :  str('a')   >   str('')   >  float(NAN)
    A<C   :  str('a')   >  str('1')   >  float(NAN)
    A<C   :  str('a')   >  str('A')   >  float(NAN)
    A<C   :  str('a')   >  str('0')   >  float(NAN)
    A<C   :  str('0')   >   str('')   >  float(NAN)
    A==C  : bool(true)  >   str('')   >  float(NAN)
    A==C  : bool(true)  >   str('')   > float(-INF)
    A==C  : bool(true)  >   str('')   >   int(-1)
    A==C  : bool(true)  >   str('')   >  float(-1)
    A==C  : bool(true)  >   array()   >  float(NAN)
    A==C  : bool(true)  >   array()   >  float(INF)
    A==C  : bool(true)  >   array()   > float(-INF)
    A==C  : bool(true)  >   array()   >   str('a')
    A==C  : bool(true)  >   array()   >    int(1)
    A==C  : bool(true)  >   array()   >   float(1)
    A==C  : bool(true)  >   array()   >   str('1')
    A==C  : bool(true)  >   array()   >   str('A')
    A==C  : bool(true)  >   array()   >   int(-1)
    A==C  : bool(true)  >   array()   >  float(-1)
    A==C  : bool(true)  >   int(0)    > float(-INF)
    A==C  : bool(true)  >   int(0)    >   int(-1)
    A==C  : bool(true)  >   int(0)    >  float(-1)
    A==C  : bool(true)  >  str('0')   >  float(NAN)
    A==C  : bool(true)  >  str('0')   > float(-INF)
    A==C  : bool(true)  >  str('0')   >   int(-1)
    A==C  : bool(true)  >  str('0')   >  float(-1)
    A==C  : bool(true)  >  float(0)   > float(-INF)
    A==C  : bool(true)  >  float(0)   >   int(-1)
    A==C  : bool(true)  >  float(0)   >  float(-1)
    A==C  :   int(1)    >  str('a')   >   str('1')
    A==C  :   int(1)    >  str('A')   >   str('1')
    A==C  :  float(1)   >  str('a')   >   str('1')
    A==C  :  float(1)   >  str('A')   >   str('1')
    A==C  :  str('a')   >  str('1')   >    int(0)
    A==C  :  str('a')   >  str('1')   >   float(0)
    A==C  :   str('')   > float(-INF) >  NULL(NULL)
    A==C  :   str('')   > float(-INF) > bool(false)
    A==C  :   str('')   >   int(-1)   >  NULL(NULL)
    A==C  :   str('')   >   int(-1)   > bool(false)
    A==C  :   str('')   >  float(-1)  >  NULL(NULL)
    A==C  :   str('')   >  float(-1)  > bool(false)
    A==C  :   array()   > float(NAN)  >  NULL(NULL)
    A==C  :   array()   > float(NAN)  > bool(false)
    A==C  :   array()   > float(INF)  >  NULL(NULL)
    A==C  :   array()   > float(INF)  > bool(false)
    A==C  :   array()   > float(-INF) >  NULL(NULL)
    A==C  :   array()   > float(-INF) > bool(false)
    A==C  :   array()   >  str('a')   >  NULL(NULL)
    A==C  :   array()   >  str('a')   > bool(false)
    A==C  :   array()   >   int(1)    >  NULL(NULL)
    A==C  :   array()   >   int(1)    > bool(false)
    A==C  :   array()   >  float(1)   >  NULL(NULL)
    A==C  :   array()   >  float(1)   > bool(false)
    A==C  :   array()   >  str('1')   >  NULL(NULL)
    A==C  :   array()   >  str('1')   > bool(false)
    A==C  :   array()   >  str('A')   >  NULL(NULL)
    A==C  :   array()   >  str('A')   > bool(false)
    A==C  :   array()   >  str('0')   >  NULL(NULL)
    A==C  :   array()   >   int(-1)   >  NULL(NULL)
    A==C  :   array()   >   int(-1)   > bool(false)
    A==C  :   array()   >  float(-1)  >  NULL(NULL)
    A==C  :   array()   >  float(-1)  > bool(false)
    A==C  :   str('')   > float(NAN)  > bool(false)
    A==C  :   str('')   > float(NAN)  >  NULL(NULL)
    A==C  :  str('A')   >  str('1')   >    int(0)
    A==C  :  str('A')   >  str('1')   >   float(0)
    A==C  :   int(0)    > float(-INF) >  NULL(NULL)
    A==C  :   int(0)    > float(-INF) > bool(false)
    A==C  :   int(0)    >   int(-1)   >  NULL(NULL)
    A==C  :   int(0)    >   int(-1)   > bool(false)
    A==C  :   int(0)    >  float(-1)  >  NULL(NULL)
    A==C  :   int(0)    >  float(-1)  > bool(false)
    A==C  :  str('0')   > float(NAN)  > bool(false)
    A==C  :  str('0')   > float(-INF) > bool(false)
    A==C  :  str('0')   >   int(-1)   > bool(false)
    A==C  :  str('0')   >  float(-1)  > bool(false)
    A==C  :  float(0)   > float(-INF) >  NULL(NULL)
    A==C  :  float(0)   > float(-INF) > bool(false)
    A==C  :  float(0)   >   int(-1)   >  NULL(NULL)
    A==C  :  float(0)   >   int(-1)   > bool(false)
    A==C  :  float(0)   >  float(-1)  >  NULL(NULL)
    A==C  :  float(0)   >  float(-1)  > bool(false)
    A===C :  str('0')   > float(NAN)  >   str('0')
    A===C :   str('')   > float(NAN)  >   str('')
    A===C :  str('a')   > float(NAN)  >   str('a')
    A===C :  str('1')   > float(NAN)  >   str('1')
    A===C :  str('A')   > float(NAN)  >   str('A')
    

    Fun string comparison: 'Queen' > 'King' > 'Jack' > 'Ace'

    Also check out PHP type comparison tables covering pairs:

    • isset() and is_null()
    • if() and empty()
    • boolean == vs. ===

    Check the differences between PHP versions live at. http://3v4l.org/MAfDu.

    0 讨论(0)
  • 2020-11-28 18:19

    PHP's comparison operators deviate from the computer-scientific definitions in several ways:

    In order to constitute an equivalence relation == has to be reflexive, symmetric and transitive:

    • PHP's == operator is not reflexive, i.e. $a == $a is not always true:

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

      Note: The fact that any comparison involving NAN is always false is not specific to PHP. It is mandated by the IEEE 754 Standard for Floating-Point Arithmetic (more info).

    • PHP's == operator is symmetric, i.e. $a == $b and $b == $a are always the same.

    • PHP's == operator is not transitive, i.e. from $a == $b and $b == $c does not follows $a == $c:

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

    In order to constitute a partial order <=/>= has to be reflexive, anti-symmetric and transitive:

    • PHP's <= operator is not reflexive, i.e. $a <= $a is not always true (Example same as for ==).

    • PHP's <= operator is not anti-symmetric, i.e. from $a <= $b and $b <= $a does not follow $a == $b:

      var_dump(NAN <= "foo"); // bool(true)
      var_dump("foo" <= NAN); // bool(true)
      var_dump(NAN == "foo"); // bool(false)
      
    • PHP's <= operator is not transitive, i.e. from $a <= $b and $b <= $c does not follow $a <= $c (Example same as for ==).

    • Extra: PHP's <= operator is not total, i.e. both $a <= $b and $b <= $a can be false:

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

    In order to constitute a strict partial order </> has to be irreflexive, asymmetric and transitive:

    • PHP's < operator is irreflexive, i.e. $a < $a is never true. Note that this is true only as of PHP 5.4. Previously INF < INF evaluated to true.

    • PHP's < operator is not asymmetric, i.e. from $a < $b does not follow !($b < $a) (Example same as for <= not being anti-symmetric).

    • PHP's < operator is not transitive, i.e. from $a < $b and $b < $c does not follow $a < $c:

      var_dump(-INF < 0);    // bool(true)
      var_dump(0 < TRUE);    // bool(true)
      var_dump(-INF < TRUE); // bool(false)
      
    • Extra: PHP's < operator is not trichotomous, i.e. all of $a < $b, $b < $a and $a == $b can be false (Example same as for <= not being total).

    • Extra: PHP's < operator can be circular, i.e. it is possible that $a < $b, $b < $c and $c < $a:

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

      Note: The above example throws a "Object of class stdClass could not be converted to double" notice.

    You can find a few nice graphs for PHP's comparison operators on PHP Sadness 52 - Comparison operators.

    As a last note, I want to point out that there are two equalities that PHP does guarantee (unlike pretty much everything else). These two always hold, simply because the compiler reduces one to the other:

    ($a > $b) == ($b < $a)
    ($a >= $b) == ($b <= $a)
    
    0 讨论(0)
  • 2020-11-28 18:19

    After your correction of the second part of your question, I leave the answer to that part to the others. I just want to give the most surprising answer to the first part of your question, i.e., whether there is an example of the < and > operators being intransitive. Here it is.

    These are all true:

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

    If < were transitive ($a < $b$b < $c$a < $c), the last line would be

    "10" < "2"
    

    but PHP tries to be kind (?!) and interpret strings as numbers whenever it can.

    It turns out that, because of the above intransitivity, sort() can sort the same elements into a different order depending on their input order, even when no two elements are == (and no element is NAN). I pointed this out in a comment to sort(), the essence of which is:

    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" )
    
    0 讨论(0)
提交回复
热议问题