【问题标题】:Unexpected result of greater than or less than comparison on PHP 8在 PHP 8 上大于或小于比较的意外结果
【发布时间】:2021-12-29 08:52:38
【问题描述】:

以下代码在 PHP 7 上返回 false,但在 PHP 8 上返回 true。有人可以解释为什么会这样吗?

var_dump("U0M262" > 100000);

【问题讨论】:

  • 这是 php 8 的新 rfc 比较 wiki.php.net/rfc/string_to_number_comparison
  • @Kevin 所以它将 100000 转换为字符串,然后进行字符串比较?
  • 是的,他们改变了行为,将它们作为非严格的字符串进行比较。因为左边的不是数字stackoverflow.com/a/66034344/3859027
  • @Kevin 一个小修正,> 运算符没有“严格”版本或模式,所以“非严格”在这里没有意义。
  • @NicoHaase 我认为这两个问题都值得保留,因为它们涵盖了同一更改的不同方面:一个涵盖了没有更改的情况,并谈到平等比较(具有===== 风格);这一个涵盖了已经改变的情况,大于和小于(只有一种风格);还有a question about the common case of empty strings

标签: php php-8


【解决方案1】:

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


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

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

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


因为 ASCII(以及兼容的编码,例如 UTF-8)的排列方式:

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

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

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

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

【讨论】:

  • 感谢您详细而清晰的解释!
猜你喜欢
  • 2021-06-18
  • 1970-01-01
  • 2018-09-20
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
  • 2019-07-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多