118

PHP以其类型杂耍而闻名。我必须承认这让我很困惑,而且我很难在比较中找出基本的逻辑/基本事物。

例如:如果$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)

对于大多数类型比较组合,这些更大/更小比较运算符没有记录,因此在这种情况下阅读手册并没有真正的帮助。

4

3 回答 3

210

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

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

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

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

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

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

  • PHP 的==运算符是不可传递的,即 from$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并不总是正确的(示例与 for 相同==)。

  • PHP 的<=运算符不是反对称的,即 from$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 的<=运算符不可传递,即 from$a <= $b且不$b <= $c跟随$a <= $c(示例与 for 相同==)。

  • 额外:PHP 的<=操作符不是 total,即两者$a <= $b$b <= $a都可以为假:

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

为了构成严格的偏序 </>必须是非自反的、不对称的和传递的:

  • PHP 的<运算符是不自反的,即$a < $a永远不是真的。请注意,这仅适用于 PHP 5.4。之前INF < INF评估为true.

  • PHP 的<运算符不是非对称的,即 from$a < $b不遵循!($b < $a)(示例与<=非反对称相同)。

  • PHP 的<运算符是不可传递的,即 from$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 的<运算符不是三分法,即 all of $a < $b$b < $a并且$a == $b可以为 false (示例与<=非 total 相同)。

  • 额外: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)
    

    注意:上面的例子抛出了“Object of class stdClass could not be convert to double”的提示。

您可以在PHP Sadness 52 -比较运算符上找到一些关于 PHP 比较运算符的漂亮图表。

最后一点,我想指出 PHP确实保证了两个等式(与几乎所有其他内容不同)。这两个始终成立,仅仅是因为编译器将一个简化为另一个:

($a > $b) == ($b < $a)
($a >= $b) == ($b <= $a)
于 2013-04-04T14:10:28.867 回答
91

PHP中没有 严格的相同比较运算符(>==<==(至少在 PHP 5.6.14 中),但有几种方法可以在检查大/小之前强制执行严格的类型检查:

  1. 检查两种变量类型if (gettype($a) === gettype($b))
  2. 强制您需要的类型转换,例如。if ((string)$a === (string)$b)
  3. 强制您需要的类型杂耍,例如。if (($a . '') === ($b . ''))

请注意:

  • 浮点精度有限
  • INF并且NANfloat下的类型
  • 一些Infinity等于一些其他Infinity(自 PHP 5.4 起)
  • 科学记数法e总是有类型的,即使数量很小float也从来没有。integer
  • 整数会PHP_INT_MAX自动转换为float
  • 在系统边界上浮动获得INF
  • 未定义变量的类型和值NULL
  • 前面的整数0从八进制转换为十进制(按约定)
  • 将包含带有前导的整数的字符串转换0 整数会去除前导0

一些奇特的比较列表:

很奇怪:
     $一个VS。$b $a>$b $a<$b $a<=$b $a>=$b $a==$b $a===$b
  浮动(NAN)浮动(-INF)假假假假假假假
  浮动(南)浮动(0)假假假假假假假
  浮动(南) 浮动(1) 假假假假假假假
  浮动(NAN) 浮动(INF) 假假假假假假
  浮动(南) 浮动(南) 假假假假假假假
  float(NAN) int(-1) 假假假假假假
  float(NAN) int(0) 假 假 假 假 假 假
  float(NAN) int(1) 假 假 假 假 假 假

相等但不相同:

     $一个VS。$b $a>$b $a<$b $a<=$b $a>=$b $a==$b $a===$b
  NULL(NULL) array() 假 假 真 真 真 假
  NULL(NULL) bool(false) false false true true true false
  NULL(NULL) float(0) 假 假 真 真 真 假
  NULL(NULL) int(0) 假 假 真 真 真 假
  NULL(NULL) str('') 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
  浮动(INF)布尔(真)假假真真真假
  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) 假 假 真 真 真 假
  str("\0") float(0) false false true true true false
   str('') float(0) 假 假 真 真 真 假
   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) 假 假 真 真 真 假
   float(1) str('01') 假 假 真 真 真 假
   float(1) str('1') 假 假 真 真 真 假
  str("\0") int(0) false false true true true false
   str('') int(0) 假 假 真 真 真 假
   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) 假 假 真 真 真 假
 str('text') int(0) false false true true true false
 str('true') int(0) false false true true true false
    int(1) str('01') 假 假 真 真 真 假
    int(1) str('1') 假 假 真 真 真 假
   str('1') str('01') false false true true true false

同时降低和提高?

     $一个VS。$b $a>$b $a<$b $a<=$b $a>=$b $a==$b $a===$b
  float(NAN) str("\0") 真真真真假假
  float(NAN) str('') true true true false false
  float(NAN) str('+') true true true false false
  float(NAN) str('-') true true true false false
  float(NAN) str('0') true true true false false
  float(NAN) str('01') true true true false false
  float(NAN) str('1') true true true false false
  float(NAN) str('false') true true true false false
  float(NAN) str('text') true true true false false
  float(NAN) str('true') true true true false false

相等且相同:

     $一个VS。$b $a>$b $a<$b $a<=$b $a>=$b $a==$b $a===$b
  NULL(NULL) NULL(NULL) 假 假 真 真 真 真
 浮动(-INF) 浮动(-INF) 假 假 真 真 真 真
  浮动(INF)浮动(INF)假假真真真真真假

更低或更高:

     $一个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) 真假假真假假
  NULL(NULL) float(1) 假真真假假假
  浮动(INF) NULL(NULL) 真假假真假假
  float(NAN) NULL(NULL) 真假假真假假
  NULL(NULL) int(-1) false true true false false false
  NULL(NULL) int(1) 假真真假假假
  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
   数组()布尔(真)假真真假假假
 浮动(-INF)数组()假真真假假假假
   数组()浮点(0)真假假真假假
   数组()浮点数(1)真假假真假假
  浮动(INF)数组()假真真假假假
  浮动(NAN)数组()假真真假假假
   array() int(-1) 真假假真假假
   array() int(0) 真假假真假假
   array() int(1) 真假假真假假
   array() str("\0") 真假假真假假
   str('') 数组() 假真真假假假
   array() str('+') true false false true false false
   array() str('-') true false false true false false
   array() str('0') 真假假真假假
   array() str('01') 真假假真假假
   array() str('1') 真假假真假假
   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
  布尔(真)布尔(假)真假假真假假
 浮动(-INF)布尔(假)真假假真假假
   float(1) bool(false) true false false true false false
  浮动(INF)布尔(假)真假假假真假假
  浮动(南)布尔(假)真假假假真假假
 bool(false) int(-1) false true true false false false
    int(1) bool(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
 浮动(-INF)浮动(0)假真真假假假
 浮动(-INF)浮动(1)假真真假假假
  浮动(INF)浮动(-INF)真假假真假假
 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
   浮动(1) 浮动(0) 真假假真假假
  浮动(INF)浮动(0)真假假真假假
   float(0) int(-1) 真假假假真假假
    int(1) float(0) 真假假真假假
   float(0) str('01') false true true false false false
   str('1') float(0) 真假假真假假
  浮动(INF)浮动(1)真假假真假假
   float(1) int(-1) 真假假真假假
   float(1) int(0) 真假假真假假
   float(1) str("\0") 真假假真假假
   str('') float(1) 假真真假假假
   float(1) str('+') 真假假真假假
   float(1) str('-') true false false true false false
   float(1) str('0') 真假假真假假
   float(1) str('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) 真假假真假假
  float(INF) int(0) 真假假假真假假
  float(INF) int(1) 真假假真假假
  float(INF) str("\0") 真假假真假假
  float(INF) str('') 真假假假真假假
  float(INF) str('+') 真假假真假假
  float(INF) str('-') 真假假真假假
  浮动(INF)str('0')真假假真假假
  浮动(INF)str('01')真假假真假假
  浮动(INF)str('1')真假假真假假
  float(INF) str('false') 真假假真假假
  浮动(INF)str('文本')真假假真假假
  float(INF) str('true') 真假假真假假
    int(0) int(-1) 真假假真假假
    int(1) int(-1) 真假假真假假
  str("\0") int(-1) 真假假真假假
   str('') int(-1) 真假假真假假
   str('+') int(-1) 真假假真假假
   str('-') int(-1) true false false true false false
   str('0') int(-1) 真假假真假假
   int(-1) str('01') false true true false false false
   str('1') int(-1) 真假假真假假
 str('false') int(-1) 真假假真假假
 str('text') int(-1) true false false true false false
 str('true') int(-1) 真假假真假假
    int(1) int(0) 真假假真假假
    int(0) str('01') false true true false false false
   str('1') int(0) 真假假真假假
    int(1) str("\0") 真假假真假假
   str('') int(1) 假真真假假假
    int(1) str('+') 真假假真假假
    int(1) str('-') 真假假真假假
    int(1) str('0') 真假假真假假
    int(1) str('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") 真假假真假假
 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('+') 真假假真假假
 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') 真假假真假假
 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难题何时:$a不大于$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 : 浮点数(NAN) > str('1') > str('0')
A<C : float(NAN) > str('A') > str('')
A<C : float(NAN) > str('A') > str('1')
A<C : 浮点数(NAN) > str('A') > str('0')
A<C : 浮点数(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 : 浮点数(1) > str('a') > str('1')
A==C : 浮点数(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:数组()>浮点(南)>空(空)
A==C:数组()>浮点(南)>布尔(假)
A==C:数组()>浮点(INF)>空(空)
A==C:数组()>浮点(INF)>布尔(假)
A==C:数组()>浮点(-INF)>空(空)
A==C:数组()>浮点(-INF)>布尔(假)
A==C : 数组() > str('a') > NULL(NULL)
A==C : 数组() > str('a') > bool(false)
A==C : 数组() > int(1) > NULL(NULL)
A==C : 数组() > int(1) > bool(false)
A==C:数组()>浮点(1)>空(空)
A==C:数组()>浮点(1)>布尔(假)
A==C : 数组() > str('1') > NULL(NULL)
A==C : 数组() > str('1') > bool(false)
A==C : 数组() > str('A') > NULL(NULL)
A==C : 数组() > str('A') > bool(false)
A==C : 数组() > str('0') > NULL(NULL)
A==C : 数组() > int(-1) > NULL(NULL)
A==C:数组()> int(-1)> bool(假)
A==C:数组()>浮点(-1)>空(空)
A==C:数组()>浮点(-1)>布尔(假)
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 : 浮点数(0) > 浮点数(-INF) > NULL(NULL)
A==C:浮点(0)>浮点(-INF)>布尔(假)
A==C : 浮点数(0) > int(-1) > NULL(NULL)
A==C : 浮点数(0) > int(-1) > bool(false)
A==C:浮点(0)>浮点(-1)>空(空)
A==C:浮点(0)>浮点(-1)>布尔(假)
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')

有趣的字符串比较:'Queen' >'King' >'Jack' >'Ace'

另请查看涵盖对的PHP 类型比较表:

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

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

于 2013-04-04T19:48:07.563 回答
23

在您更正问题的第二部分后,我将这部分的答案留给其他人。我只想对你的问题的第一部分给出最令人惊讶的答案,即是否存在<and>运算符不及物的例子。这里是。

这些都是true

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

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

"10" < "2"

但是 PHP 试图变得友善(?!)并尽可能将字符串解释为数字。

事实证明,由于上述不传递性,sort()可以根据输入顺序将相同的元素排序为不同的顺序,即使没有两个元素是==(并且没有元素是 NAN)。我在对 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" )
于 2013-04-06T22:29:52.450 回答