在PHP中进行types杂耍和(严格)大于/小于比较

PHP以其types杂耍而闻名。 我必须承认这使我困惑,而且我很难在比较中找出基本的逻辑/基本的东西。

例如:如果$a > $b为真, $b > $c为真,那么它是否意味着$a > $c 总是为真?

遵循基本的逻辑,我会说是的,但是我感到困惑,我不太信任在这个PHP。 也许有人可以提供一个例子,如果不是这样的话?

另外我想知道严格的小于和严格的大于运算符(因为它们的含义被严格地描述为我只知道在过去从等式比较),如果左和右操作数交换严格不平等的价值观:

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

对于大多数types比较组合,这些较大/较小的比较运算符都没有logging,因此在这种情况下阅读手册并不是很有帮助。

PHP的比较运算符在几个方面偏离了计算机科学的定义:

为了构成一个等价关系, ==必须是自反的,对称的和传递的:

  • PHP的==运算符不是自反的 ,即$a == $a并不总是对的:

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

    注意:任何涉及NAN比较总是false的事实并不是PHP特有的。 它是由IEEE 754浮点运算标准( 更多信息 )规定的。

  • PHP的==运算符是对称的 ,即$a == $b$b == $a总是相同的。

  • PHP的==运算符不是传递的 ,即从$a == $b$b == $c不符合$a == $c

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

为了构成偏序 <= / >=必须是自反的,反对称的和传递性的:

  • PHP的<=运算符不是自反的 ,即$a <= $a并不总是为真(例子与==相同)。

  • PHP的<=运算符不是反对称的 ,即从$a <= $b$b <= $a不符合$a == $b

     var_dump(NAN <= "foo"); // bool(true) var_dump("foo" <= NAN); // bool(true) var_dump(NAN == "foo"); // bool(false) 
  • PHP的<=运算符不是传递的 ,即从$a <= $b$b <= $c不跟随$a <= $c (例子与==相同)。

  • 额外:PHP的<=运算符不是总数 ,即$a <= $b$b <= $a都可以是false:

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

为了构成严格的偏序 ,必须是非reflection的,不对称的和传递性的:

  • PHP的<运算符是不reflection的 ,即$a < $a永远不会是真的。 请注意,这仅仅是从PHP 5.4开始的 。 以前INF < INF评估为true

  • PHP的<运算符不是不对称的 ,即从$a < $b不跟随!($b < $a) (示例与<=不是反对称)相同。

  • PHP的<操作符不是传递的 ,即从$a < $b$b < $c不跟随$a < $c

     var_dump(-INF < 0); // bool(true) var_dump(0 < TRUE); // bool(true) var_dump(-INF < TRUE); // bool(false) 
  • 额外:PHP的<运算符不是三元的 ,也就是说, $a < $b$b < $a$a == $b都可以是假的(例子与<=不是总和)相同。

  • 额外:PHP的<运算符可以是循环的 ,也就是说$a < $b$b < $c$c < $a

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

    注意:上面的例子抛出了“stdClass类的对象无法转换为double”通知。

您可以在PHP悲伤52 -比较运算符上find一些关于PHP比较运算符的漂亮图表。

作为最后一点,我想指出的是,PHP 确实有两个平等点(几乎与其他所有方面不同)。 这两者总是成立,只是因为编译器将一个减less到另一个:

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

PHP中没有 严格相同的比较运算符( >==<==(至lessPHP 5.6.14) ,但有几种方法在检查Greater / Lower之前强制进行严格types检查

  1. if (gettype($a) === gettype($b))检查两个variablestypes
  2. 强制你需要的types转换例如。 if ((string)$a === (string)$b)
  3. 强制你需要的types,例如。 if (($a . '') === ($b . ''))

请注意:

  • 浮点精度有限
  • INFNAN是ieee754下的浮点types
  • 有些Infinity等于其他Infinity (自PHP 5.4以来)
  • 科学记数法e始终为floattypes,即使数字很小也不会integer
  • 整数遍历PHP_INT_MAX会自动转换为float
  • 漂浮在系统的边界上获得INF
  • 未定义variables的types和值为NULL
  • 0结尾的整数从八进制转换为十进制(按照惯例)
  • 将包含具有前导0的整数的string转换整数将删除前导0

一些奇特的比较列表:

很奇怪:
      $ a VS.  $ b $ a> $ b $ a <$ b $ a <= $ b $ a> = $ b $ a == $ b $ a === $ b
  浮点(NAN)浮点数(-INF)假假假假假假假
  浮点(NAN)浮点(0)假假假假假假假
   float(NAN)float(1)false false false false false
  浮点(NAN)浮点(INF)假假假假假假假
  浮点(NAN)浮点(NAN)假假假假假假假
   float(NAN)int(-1)false false false false false
   float(NAN)int(0)false false false false false
   float(NAN)int(1)false false false false false

相同但不相同:

      $ 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 false
   NULL(NULL)float(0)false false true true false
   NULL(NULL)int(0)false false true true false
   NULL(NULL)str('')false false true true false
    array()bool(false)false false true true false
  bool(false)float(0)false false true true false
  bool(false)int(0)false false true true false
    str('')bool(false)false false true true false
  bool(false)str('0')false false true true false
  float(-INF)bool(true)false false true true true false
   bool(true)float(1)false false true true false
   float(INF)bool(true)false false true true false
   float(NAN)bool(true)false false true true true false
   bool(true)int(-1)false false true true false
   bool(true)int(1)false false true true false
   bool(true)str(“\ 0”)false false true true false
   bool(true)str('+')false false true true true false
   bool(true)str(' - ')false false 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 false
  str('true')bool(true)false false true true false
 int(0)float(0)false false true true false 
    str(“\ 0”)float(0)false false true true false 
     str('')float(0)false false true true false 
     str('+')float(0)false false true true true false 
     str(' - ')float(0)false false true true false 
     str('0')float(0)false false true true false 
   str('false')float(0)false false true true false 
   str('text')float(0)false false true true false 
   str('true')float(0)false false true true false 
      int(1)float(1)false false 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 false 
     str('')int(0)false false true true false 
     str('+')int(0)false false true true false 
     str(' - ')int(0)false false true true false 
      int(0)str('0')false false true true true false 
   str('false')int(0)false false true true false 
   str('text')int(0)false false true true false 
   str('true')int(0)false false 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 false

同时降低和更大?

      $ 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

相同和相同:

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

更低或更高:

      $ a VS.  $ b $ a> $ b $ a <$ b $ a <= $ b $ a> = $ b $ a == $ b $ a === $ b
   NULL(NULL)bool(true)false true true false false
  float(-INF)NULL(NULL)true false false true false false
   NULL(NULL)float(1)false true true false false
   float(INF)NULL(NULL)true false false true false false
   float(NAN)NULL(NULL)true false false false false
   NULL(NULL)int(-1)false true true false false
   NULL(NULL)int(1)false true true false false
   NULL(NULL)str(“\ 0”)false true true false false
   NULL(NULL)str('+')false true true false false
   NULL(NULL)str(' - ')false true true false false
   NULL(NULL)str('0')false true true false false
   NULL(NULL)str('01')false true true false false
   NULL(NULL)str('1')false true true false false
   NULL(NULL)str('false')false true true false false
   NULL(NULL)str('text')false true true false false
   NULL(NULL)str('true')false true true false false
 array()bool(true)false true true false false 
   float(-INF)数组()false false true false false false 
     array()float(0)true false false true false 
     array()float(1)true false false true false 
    float(INF)array()false true true false false 
    float(NAN)array()false true true false false 
     array()int(-1)true false false true false 
     array()int(0)true false false true false 
     array()int(1)true false false true false 
     array()str(“\ 0”)true false false true false false 
     str('')array()false true true false false 
     array()str('+')true false false true false false 
     array()str(' - ')true false false true false 
     array()str('0')true false false false false 
     array()str('01')true false false true false 
     array()str('1')true false false false false 
     array()str('false')true false false true false 
     array()str('text')true false false false false 
     array()str('true')true false false 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
  bool(false)str('+')false true true false false false
  bool(false)str(' - ')false true true 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 false false
  str('true')bool(false)true false false false false
   bool(true)float(0)true false false true false
   bool(true)int(0)true false false true false
    str('')bool(true)false true true false false
   bool(true)str('0')true false false true false false
  float(-INF)float(0)false true true false false
  float(-INF)float(1)false true true false false
   float(INF)float(-INF)true false false true false false
  float(-INF)int(-1)false true true false false
  float(-INF)int(0)false true true false false
  float(-INF)int(1)false true true false false
  float(-INF)str(“\ 0”)false true true false false
  float(-INF)str('')false true true false false
  float(-INF)str('+')false true true false false
  float(-INF)str(' - ')false true true false false
  float(-INF)str('0')false true true false false
  float(-INF)str('01')false true true false false
  float(-INF)str('1')false true true false false
  float(-INF)str('false')false true true false false
  float(-INF)str('text')false true true false false
  float(-INF)str('true')false true true false false
    float(1)float(0)true false false true false
   float(INF)float(0)true false false true false
    float(0)int(-1)true false false true false
     int(1)float(0)true false false true false
    float(0)str('01')false true true false false
    str('1')float(0)true false false true false
   float(INF)float(1)true false false true false false
    float(1)int(-1)true false false true false
    float(1)int(0)true false false true false
    float(1)str(“\ 0”)true false false true false false
    str('')float(1)false true true false false
    float(1)str('+')true false false true false
    float(1)str(' - ')true false false true false
    float(1)str('0')true false false true false
    float(1)str('false')true false false true false false
  str('text')float(1)false true true false false
  str('true')float(1)false true true false false
   float(INF)int(-1)true false false true false
   float(INF)int(0)true false false true 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 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 false false
     int(0)int(-1)true false false true false
     int(1)int(-1)true false false true false
   str(“\ 0”)int(-1)true false false true false
    str('')int(-1)true false false true false
    str('+')int(-1)true false false true false
    str(' - ')int(-1)true false false true false
    str('0')int(-1)true false false true false
    int(-1)str('01')false true true false false
    str('1')int(-1)true false false true false
  str('false')int(-1)true false false true false
  str('text')int(-1)true false false true false
  str('true')int(-1)true false false true false
     int(1)int(0)true false false true false
     int(0)str('01')false true true false false
    str('1')int(0)true false false true false
     int(1)str(“\ 0”)true false false true false false
    str('')int(1)false true true false false
     int(1)str('+')true false false true false false
     int(1)str(' - ')true false false true false
     int(1)str('0')true false false true false
     int(1)str('false')真假假真真假假
 str('text')int(1)false true true false false
  str('true')int(1)false true true false false
    str('')str(“\ 0”)false true true 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
   str(“\ 0”)str('01')false true true 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
    str('')str(' - ')false true true false false
    str('')str('0')false true true false false
    str('')str('01')false true true false false
    str('')str('1')false true true false false false
    str('')str('false')false true true false false
    str('')str('text')false true true false false
    str('')str('true')false true true false false
 str(' - ')str('+')true false false true false
    str('+')str('0')false true true false false false
    str('+')str('01')false true true 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
    str(' - ')str('01')false true true 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
    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
  str('true')str('01')true false false true false false
    str('1')str('false')false true true 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 false false

$a > $b > $c当以下情况$a时: $a不大于$c

 A&ltC:float(NAN)> str('a')> str('')
 A&ltC:float(NAN)> str('a')> str('1')
 A&ltC:float(NAN)> str('a')> str('A')
 A&ltC:float(NAN)> str('a')> str('0')
 A&ltC:float(NAN)> str('1')> str('')
 A&ltC:float(NAN)> str('1')> str('0')
 A&ltC:float(NAN)> str('A')> str('')
 A&ltC:float(NAN)> str('A')> str('1')
 A&ltC:float(NAN)> str('A')> str('0')
 A&ltC:float(NAN)> str('0')> str('')
 A&ltC:str('')> float(NAN)> str('a')
 A&ltC:str('')> float(NAN)> str('1')
 A&ltC:str('')> float(NAN)> str('A')
 A&ltC:str('')> float(NAN)> str('0')
 A&ltC:str('a')> str('')> float(NAN)
 A&ltC:str('a')> str('1')> float(NAN)
 A&ltC:str('a')> str('A')> float(NAN)
 A&ltC:str('a')> str('0')> float(NAN)
 A&ltC: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')

有趣的string比较:“女王” > “国王” > “杰克” > “王牌”

另外检查一下PHPtypes比较表,包括对:

  • isset()is_null()
  • if()empty()
  • 布尔=====

检查PHP版本之间的差异。 http://3v4l.org/MAfDu

在你对问题的第二部分进行修改之后,我将这一部分的答案留给其他人。 我只想给你的问题的第一部分提供最令人惊讶的答案,即是否存在一个<>操作符不灵敏的例子。 这里是。

这些都是true

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

如果<传递( $a < $b ^ $b < $c $a < $c ),最后一行是

 "10" < "2" 

但是PHP会尽可能的善良(?!),并且尽可能的将string解释为数字。

事实certificate,由于上述不可行性, 即使没有两个元素== (且没有元素是NAN), sort()也可以根据它们的input顺序将相同的元素sorting为不同的顺序。 我在对sort()的评论中指出这一点,其实质是:

 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" )