PHP 类型比较

`==` 与 `===` 的差别、松散比较表、以及 8.0 的变化。

Beginner
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.

经典陷阱表

ExpressionPHP 7PHP 8Why
0 == "a"truefalse8.0 改了字符串与数字比较规则
"1" == "01"truetrue都是数字字符串
"abc" == 0truefalse非数字字符串不再等于 0
null == falsetruetrue都转成 false
"" == nulltruetrue都转成空
[] == falsetruetrue空数组为假
"1" == "1 "truetrue数字字符串忽略尾部空白
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)
匹配到 0

in_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 == "");         // true
Output
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.

Friends & Partners