PHP 类型比较
`==` 与 `===` 的差别、松散比较表、以及 8.0 的变化。
Key Points`==` 会先转换类型再比较,`===` 要求类型和值都相同——永远优先用 `===`。
两种比较
PHP
<?php
var_dump(0 == "a"); // PHP 8: false(7.x 是 true!)
var_dump("1" == "01"); // true,都是数字字符串
var_dump("10" == "1e1"); // true,都转成 10
var_dump(100 == "1e2"); // true
echo "---\n";
var_dump(0 === "a");
var_dump("1" === "01");
var_dump(100 === "100");
var_dump(100 === 100);Output
bool(false)
bool(true)
bool(true)
bool(true)
---
bool(false)
bool(false)
bool(false)
bool(true)== converts a numeric string to a number when compared with a number, and compares two numeric strings numerically — hence "10" == "1e1" is true.
经典陷阱表
| Expression | PHP 7 | PHP 8 | Why |
|---|---|---|---|
0 == "a" | true | false | 8.0 改了字符串与数字比较规则 |
"1" == "01" | true | true | 都是数字字符串 |
"abc" == 0 | true | false | 非数字字符串不再等于 0 |
null == false | true | true | 都转成 false |
"" == null | true | true | 都转成空 |
[] == false | true | true | 空数组为假 |
"1" == "1 " | true | true | 数字字符串忽略尾部空白 |
PHP 8.0 fixed the infamous
0 == "a" (which caused countless auth bypasses). But null == false and "" == null still hold — **always use ===**.实际踩坑场景
PHP
<?php
// 坑 1:用户输入的 "0" 被当成空
$input = "0";
if (empty($input)) {
echo "被当成空了\n";
}
if ($input === "") {
echo "这才是真的空\n";
} else {
echo "不是空字符串\n";
}
// 坑 2:in_array 默认松散比较
$haystack = [0, 1, 2];
var_dump(in_array("abc", $haystack)); // PHP 8: false
var_dump(in_array("1", $haystack)); // true
var_dump(in_array("1", $haystack, true)); // false(严格)
// 坑 3:switch 用松散比较
$v = "0";
switch ($v) {
case 0:
echo "匹配到 0\n";
break;
}Output
被当成空了
不是空字符串
bool(false)
bool(true)
bool(false)
匹配到 0in_array and array_search compare loosely by default; pass true as the third argument for strict. This is one of the most common security holes in PHP — in_array($role, ['admin']) can be bypassed.
比较规则速查
PHP
<?php
// 同类型:直接比
var_dump(1 < 2); // true
var_dump("abc" < "abd"); // true(字典序)
// 数字 vs 数字字符串:转成数字
var_dump(10 == "10"); // true
var_dump(10 == "10.0"); // true
// 数字 vs 非数字字符串:PHP 8 起转成字符串比较
var_dump(0 == "abc"); // false
var_dump(0 == ""); // false
// 布尔与任何值:都转成布尔
var_dump(true == "任意非空"); // true
var_dump(false == ""); // true
// null 与字符串:null 转成 ""
var_dump(null == ""); // trueOutput
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)true == "anything non-empty" is always true, so if ($flag == true) is meaningless — write if ($flag). Beware any comparison against a boolean.两种比较
PHP
<?php
var_dump(0 == "a"); // PHP 8: false(7.x 是 true!)
var_dump("1" == "01"); // true,都是数字字符串
var_dump("10" == "1e1"); // true,都转成 10
var_dump(100 == "1e2"); // true
echo "---\n";
var_dump(0 === "a");
var_dump("1" === "01");
var_dump(100 === "100");
var_dump(100 === 100);Output
bool(false)
bool(true)
bool(true)
bool(true)
---
bool(false)
bool(false)
bool(false)
bool(true)== 的规则是:如果一边是数字、另一边是数字字符串,就把字符串转成数字比较;如果两边都是数字字符串,也按数字比。所以 "10" == "1e1" 是 true。
经典陷阱表
| 表达式 | PHP 7 | PHP 8 | 原因 |
|---|---|---|---|
0 == "a" | true | false | 8.0 改了字符串与数字比较规则 |
"1" == "01" | true | true | 都是数字字符串 |
"abc" == 0 | true | false | 非数字字符串不再等于 0 |
null == false | true | true | 都转成 false |
"" == null | true | true | 都转成空 |
[] == false | true | true | 空数组为假 |
"1" == "1 " | true | true | 数字字符串忽略尾部空白 |
PHP 8.0 修掉了
0 == "a" 这个臭名昭著的坑(它曾导致无数鉴权绕过漏洞)。但 null == false、"" == null 依然成立,所以**比较还是必须用 ===**。实际踩坑场景
PHP
<?php
// 坑 1:用户输入的 "0" 被当成空
$input = "0";
if (empty($input)) {
echo "被当成空了\n";
}
if ($input === "") {
echo "这才是真的空\n";
} else {
echo "不是空字符串\n";
}
// 坑 2:in_array 默认松散比较
$haystack = [0, 1, 2];
var_dump(in_array("abc", $haystack)); // PHP 8: false
var_dump(in_array("1", $haystack)); // true
var_dump(in_array("1", $haystack, true)); // false(严格)
// 坑 3:switch 用松散比较
$v = "0";
switch ($v) {
case 0:
echo "匹配到 0\n";
break;
}Output
被当成空了
不是空字符串
bool(false)
bool(true)
bool(false)
匹配到 0in_array 和 array_search 默认松散比较,第三个参数传 true 才严格。这是 PHP 项目里最常见的安全隐患之一——权限数组里 in_array($role, ['admin']) 可能被 0 之类绕过。
比较规则速查
PHP
<?php
// 同类型:直接比
var_dump(1 < 2); // true
var_dump("abc" < "abd"); // true(字典序)
// 数字 vs 数字字符串:转成数字
var_dump(10 == "10"); // true
var_dump(10 == "10.0"); // true
// 数字 vs 非数字字符串:PHP 8 起转成字符串比较
var_dump(0 == "abc"); // false
var_dump(0 == ""); // false
// 布尔与任何值:都转成布尔
var_dump(true == "任意非空"); // true
var_dump(false == ""); // true
// null 与字符串:null 转成 ""
var_dump(null == ""); // trueOutput
bool(true)
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)true == "任意非空" 恒为 true。所以 if ($flag == true) 这种写法毫无意义,直接 if ($flag) 即可。反过来说,任何「与布尔比较」的地方都应该警惕。