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

后端 未结 3 1029
执念已碎
执念已碎 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.

提交回复
热议问题