PHP 8 上大于或小于比较的意外结果

Unexpected result of greater than or less than comparison on PHP 8

下面的 returns false 在 PHP 7 但 true 在 PHP 8。有人可以解释为什么会这样吗?

var_dump("U0M262" > 100000);

字符串和数字的比较没有明显正确的结果。在许多语言中,它只会给出一个错误;在其他情况下,包括 PHP,该语言试图通过将两个操作数转换为同一类型来理解它,但这涉及判断“更喜欢”哪种类型。


从历史上看,PHP 更喜欢比较数字而不是比较字符串:它将 "U0M262" > 100000 视为 (int)"U0M262" > 100000。由于(int)"U0M262"没有明显的值,所以求值为0,表达式变为0 > 100000,为false。

从 PHP 8 开始,this behaviour has changed 和 PHP 现在只对“数字字符串”使用数字比较,例如"42" 显然“看起来像” 42.

由于 "U0M262" 不符合数字字符串的要求,"U0M262" > 100000 现在被视为 "U0M262" > (string)100000。这会对两个字符串的排序顺序进行字节比较,并发现由于“U”在 ASCII 中出现在“1”之后(以及任何 ASCII 派生编码,包括 UTF -8),结果为真。


由于ASCII(以及UTF-8等兼容编码)的排列方式:

  • 以控制字符或 space 开头的字符串将“小于”任何数字
  • 以字母开头的字符串将“多于”任何数字
  • 以任何“!”开头的字符串 # $ % & ' ( ) * + , - 。 /”将“小于”任何数字
  • 对于以数字开头的字符串,需要查看各个字节
  • 任何其他字符串将“大于”任何数字

与以往一样,您可以告诉 PHP 您想要进行哪种比较,并使用显式转换在所有版本中获得正确的行为:

var_dump((int)"U0M262" > (int)100000); // bool(false)
var_dump((string)"U0M262" > (string)100000); // bool(true)

(显然,如果您对双方都进行硬编码,这毫无意义,但假设其中一方或双方都是变量,这就是您的做法。)