为什么 PHP 8 将 42 == " 42" 视为真?
Why does PHP 8 treat 42 == " 42" as true?
PHP 8 已发布。它对相等运算符的行为进行了更改。根据 the documentation,这是它现在的行为方式:
Non-strict comparisons between numbers and non-numeric strings now work by casting the number to string and comparing the strings.
但是,此表达式在 PHP 8 和 PHP 的早期版本中的计算结果为真:
42 == " 42" // true
这对我来说没有意义。根据文档,数字应该转换为字符串 "42"
,这肯定不等于字符串 " 42"
,对吧?
简答:
在PHP 8和PHP 7中,42 == " 42"
为真,在PHP 7和PHP 8中,"42" == " 42"
是真的。
长答案:
我认为您对相等运算符 ==
在 PHP 中的工作方式有误解。在 PHP 8 和 PHP 的早期版本中,相等运算符对待数字字符串的方式与其他字符串不同:
<?php
// the == operator does type juggling and also handles numerical strings differently:
var_export("42" == "42"); // true
var_export(42 == "42"); // true
var_export("42" == " 42"); // true
var_export("42" == "42 "); // false in PHP 7 and true in PHP 8
var_export("42" == "042"); // true
var_export("10" == "1e1"); // true
var_export("abc" == " abc"); // false
var_export("42" == "abc 42"); // false
echo "\n";
// the === operator does not do type juggling and does not handle numerical strings differently:
var_export("42" === "42"); // true
var_export(42 === "42"); // false
var_export("42" === " 42"); // false
var_export("42" === "42 "); // false
var_export("42" === "042"); // false
var_export("10" === "1e1"); // false
var_export("abc" === " abc"); // false
var_export("42" === "abc 42"); // false
echo "\n";
即使在 PHP 8 中,==
运算符也会进行类型转换,并且它以不同的方式处理数字字符串。这个原则没有改变。 PHP 8 中发生的变化是:
- 相等运算符
==
在 PHP 8 中的行为与在 PHP 7 中的行为不同,用于比较数字和非数字字符串
- 什么字符串被认为是数字字符串在PHP8
中是不同的
关于后一点,请阅读:
Numeric string handling has been altered [in PHP 8] to be more intuitive and less error-prone. Trailing whitespace is now allowed in numeric strings for consistency with how leading whitespace is treated. This mostly affects:
- The
is_numeric()
function
- String-to-string comparisons
- Type declarations
- Increment and decrement operations
您引用的文档实际上是正确的,但可能会更清楚:
Non-strict comparisons between numbers and non-numeric strings now work by casting the number to string and comparing the strings.
我将关键短语“非数字字符串”加粗了。
在 PHP 的各个部分中,有一个“数字字符串”的概念作为一种伪类型:任何 看起来像 数字的字符串可以被语言的一部分视为一个。这是为了帮助 PHP 的主要用例,即从网络请求中获取数据(始终是字符串)并在操作中使用它(可能希望将其视为数字)。
它发挥作用的地方之一是 ==
运算符,它试图对您要比较的内容“聪明”。
如果 PHP 确定 ==
运算符的两边都是数字 或 数字字符串,它将通过将它们都转换为来执行比较整数(或浮点数,如果适用)并查看它们是否具有相同的 numeric 值。 “数字字符串”的定义非常广泛,并且允许有前导空格;从 PHP 8 开始,它现在还允许尾随空格,以保持一致性。
因此在您的示例中," 42"
是一个“数字字符串”,42
是一个实际数字,因此执行的比较是 (int)" 42" === 42
你的报价中描述的变化是针对一侧是实际数字(整数或浮点数)而另一侧是非数字字符串的情况,即PHP 认为“看起来不像数字”。在 PHP 的旧版本中,这会 也 转换为 int,因此 "hello" == 0
会评估 (int)"hello" === 0
,即 true
。在 PHP 8 中,this case 转换为字符串,因此 "hello" == 0
将计算 "hello" === (string)0
,即 false
.
PHP 8 已发布。它对相等运算符的行为进行了更改。根据 the documentation,这是它现在的行为方式:
Non-strict comparisons between numbers and non-numeric strings now work by casting the number to string and comparing the strings.
但是,此表达式在 PHP 8 和 PHP 的早期版本中的计算结果为真:
42 == " 42" // true
这对我来说没有意义。根据文档,数字应该转换为字符串 "42"
,这肯定不等于字符串 " 42"
,对吧?
简答:
在PHP 8和PHP 7中,42 == " 42"
为真,在PHP 7和PHP 8中,"42" == " 42"
是真的。
长答案:
我认为您对相等运算符 ==
在 PHP 中的工作方式有误解。在 PHP 8 和 PHP 的早期版本中,相等运算符对待数字字符串的方式与其他字符串不同:
<?php
// the == operator does type juggling and also handles numerical strings differently:
var_export("42" == "42"); // true
var_export(42 == "42"); // true
var_export("42" == " 42"); // true
var_export("42" == "42 "); // false in PHP 7 and true in PHP 8
var_export("42" == "042"); // true
var_export("10" == "1e1"); // true
var_export("abc" == " abc"); // false
var_export("42" == "abc 42"); // false
echo "\n";
// the === operator does not do type juggling and does not handle numerical strings differently:
var_export("42" === "42"); // true
var_export(42 === "42"); // false
var_export("42" === " 42"); // false
var_export("42" === "42 "); // false
var_export("42" === "042"); // false
var_export("10" === "1e1"); // false
var_export("abc" === " abc"); // false
var_export("42" === "abc 42"); // false
echo "\n";
即使在 PHP 8 中,==
运算符也会进行类型转换,并且它以不同的方式处理数字字符串。这个原则没有改变。 PHP 8 中发生的变化是:
- 相等运算符
==
在 PHP 8 中的行为与在 PHP 7 中的行为不同,用于比较数字和非数字字符串 - 什么字符串被认为是数字字符串在PHP8 中是不同的
关于后一点,请阅读:
Numeric string handling has been altered [in PHP 8] to be more intuitive and less error-prone. Trailing whitespace is now allowed in numeric strings for consistency with how leading whitespace is treated. This mostly affects:
- The
is_numeric()
function- String-to-string comparisons
- Type declarations
- Increment and decrement operations
您引用的文档实际上是正确的,但可能会更清楚:
Non-strict comparisons between numbers and non-numeric strings now work by casting the number to string and comparing the strings.
我将关键短语“非数字字符串”加粗了。
在 PHP 的各个部分中,有一个“数字字符串”的概念作为一种伪类型:任何 看起来像 数字的字符串可以被语言的一部分视为一个。这是为了帮助 PHP 的主要用例,即从网络请求中获取数据(始终是字符串)并在操作中使用它(可能希望将其视为数字)。
它发挥作用的地方之一是 ==
运算符,它试图对您要比较的内容“聪明”。
如果 PHP 确定 ==
运算符的两边都是数字 或 数字字符串,它将通过将它们都转换为来执行比较整数(或浮点数,如果适用)并查看它们是否具有相同的 numeric 值。 “数字字符串”的定义非常广泛,并且允许有前导空格;从 PHP 8 开始,它现在还允许尾随空格,以保持一致性。
因此在您的示例中," 42"
是一个“数字字符串”,42
是一个实际数字,因此执行的比较是 (int)" 42" === 42
你的报价中描述的变化是针对一侧是实际数字(整数或浮点数)而另一侧是非数字字符串的情况,即PHP 认为“看起来不像数字”。在 PHP 的旧版本中,这会 也 转换为 int,因此 "hello" == 0
会评估 (int)"hello" === 0
,即 true
。在 PHP 8 中,this case 转换为字符串,因此 "hello" == 0
将计算 "hello" === (string)0
,即 false
.