PHP 类型比较

下面对 PHP 中的 类型比较 做一次深入详解,涵盖各种比较运算符、松散比较(type juggling)规则、特殊情况及最佳实践。


一、比较运算符概览

运算符描述
==等于(松散比较)
===全等(严格比较,类型与值都相同)
!=不等于(松散比较)
!==不全等(严格比较)
<小于
>大于
<=小于等于
>=大于等于
<=>太空船操作符(PHP 7+),返回–1/0/1
// 示例
var_dump( 1 == "1" );   // true   (值相同,类型可转换)
var_dump( 1 === "1" );  // false  (类型不同)
var_dump(2 < 3);        // true
var_dump(2 <=> 3);      // -1
var_dump(3 <=> 3);      // 0
var_dump(4 <=> 3);      // 1

二、松散比较(== / !=)规则

松散比较时,PHP 会按以下优先级进行类型转换,再比较:

  1. 若两者都是数值或数值字符串,都转换为数值后比较
  2. 若其中一个是布尔值,另一方也转换为布尔后比较
  3. 若其中一个是 NULL,另一方转换为 NULL 后比较
  4. 数组与对象 按各自规则(见下文)
  5. 其它情况,将两者都转换为字符串后比较

1. 数字与字符串

var_dump("123" == 123);    // true   ("123" → 123)
var_dump("  10px" == 10);  // true   (前导空白可,遇非数字停止:10)
var_dump("foo" == 0);      // true   (非数字字符串转为 0)
var_dump("0" == false);    // true   ("0"→0, false→0)
var_dump("" == 0);         // true   (""→0)

2. 布尔比较

var_dump(0 == false);      // true
var_dump("" == false);     // true
var_dump([] == false);     // true
var_dump("php" == true);   // true   (非空非“0”字符串→true)
var_dump("0" == false);    // true

3. NULL 比较

var_dump(NULL == false);   // true   (NULL→false)
var_dump(NULL == 0);       // true   (NULL→0)
var_dump(NULL == "");      // true   (NULL→"")
var_dump(NULL == []);      // true   (NULL→[]?)

注意NULL 在松散比较时,会和大多数空值都等价。

4. 数组与对象

  • 空数组 vs 空字符串、0、false、NULLvar_dump([] == false); // true var_dump([] == ""); // true var_dump([] == null); // true
  • 非空数组之间,按元素逐一比较长度和值
  • 对象 vs 对象,要求同一类且所有属性松散相等
  • 数组 vs 对象,会先转换对象为数组再比较

三、严格比较(=== / !==

严格比较无需类型转换,只有类型和值都完全相同时才为 true

var_dump(0 === false);     // false  (类型不同)
var_dump("" === false);    // false
var_dump(NULL === false);  // false
var_dump([] === false);    // false
var_dump([1,2] === [1,2]); // true

最佳实践:尽量在业务逻辑中使用严格比较,避免因隐式转换导致意外。


四、太空船操作符 <=>(PHP 7+)

  • 用于整洁地实现三向比较,常用于排序函数中。
  • 语义:
    • 若左 < 右,返回 -1
    • 相等返回 0
    • 左 > 右,返回 1
echo 1 <=> 2;  // -1
echo 2 <=> 2;  // 0
echo 3 <=> 2;  // 1

// 排序示例
$arr = [3,1,2];
usort($arr, function($a,$b){ return $a <=> $b; });
print_r($arr); // [1,2,3]

五、特殊与边缘案例

比较结果原因
"php" == truetrue非空非“0”字符串 → true
"php" === truefalse类型不同
" 123abc" == 123true前导空白忽略,遇非数字停在 abc
" " == 0true仅空白 → 转为 "" → 0
" " == falsetrue空字符串 → false
0 == "a"true非数字字符串 → 0
[] == ""true空数组 → “”
[0] == falsetrue数组转换为单元素字符串 “0”? → 0? 与 false 相等
new A == new Bfalse不同类对象

六、常见陷阱与建议

  1. 不要用 == 比较浮点数
    浮点精度问题,建议使用 abs($a - $b) < $epsilon
  2. 避免将数字与用户输入的任意字符串直接比较
    比如 $_GET['id'] == 0,会把 "foo" 误判为 0
  3. 对空值用 === 或 显式函数if (is_null($x)) { … } if ($x === "") { … } if (empty($x)) { … } // 但 empty() 会将 0 视为空
  4. 推荐开启严格模式declare(strict_types=1); 并在函数中使用类型声明,减少类型错误。

七、实践示例

declare(strict_types=1);

function compare($a, $b) {
    echo var_export($a, true) . " == " . var_export($b, true) . " ? ";
    var_dump($a == $b);
    echo var_export($a, true) . " === " . var_export($b, true) . " ? ";
    var_dump($a === $b);
    echo "\n";
}

compare("0", false);
compare("", 0);
compare("php", true);
compare(null, []);
compare([1,2], [1,2]);
compare(1.0, 1);

输出:

'0' == false ? true
'0' === false ? false

'' == 0 ? true
'' === 0 ? false

'php' == true ? true
'php' === true ? false

NULL == array () ? true
NULL === array () ? false

array (1,2) == array (1,2) ? true
array (1,2) === array (1,2) ? true

1.0 == 1 ? true
1.0 === 1 ? false

小结

  • 松散比较 会进行类型转换,易出意外;
  • 严格比较 既比较类型又比较值,更安全;
  • 对于排序场景,可用 <=>
  • 业务逻辑中 推荐 一律使用 ===/!==,并结合类型声明与严格模式,避免隐式类型陷阱。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注