应始终优先使用===进行严格比较,因为==会隐式类型转换导致意外结果,如'0'==0为true、[]==false为true,易引发逻辑错误和安全漏洞。

这类比较在 PHP 里不会报错,但结果往往和直觉相反,而且升级到 PHP 8.0 后行为更不一致——不是“全变严格”,而是“部分更严、部分照旧”,最容易漏掉测试。
字符串与数字用 == 比较时的隐式转换规则
PHP 遇到 == 且两边类型不同时,会尝试把字符串转成数字再比。转换不是全量解析,而是“从头取连续数字”:
- 以数字开头(如
"123abc")→ 提取123,后续字符直接丢弃 - 不以数字开头(如
"abc123")→ 整体转为0 - 含十六进制前缀(如
"0x01")→ PHP 7.4+ 不再识别为数字,转成0;PHP 7.2 会识别为1 - 科学计数法前缀(如
"0e123")→ 被当作浮点数0.0,所以"0e123" == 0为true
所以 '123abc' == 123 是 true,但 '123a' == 123 在 PHP 8.0 也是 true(仍按老规则截断),而 '123abc456' == 123456 却是 false(因为只取了开头 123)。
常见踩坑场景:权限校验、ID 匹配、表单验证
这些地方如果用了松散比较,就容易被绕过或误拒:
- 用户传入
id=123abc,后端写if ($_GET['id'] == $db_row['id'])→ 匹配成功,实际查的是123的记录 - API 接口校验 token:
if ($input_token == $valid_token),若两者都是0e...开头,可能恒等(MD5 碰撞) - 表单提交数字字段,前端没校验,用户输
"123px",后端if ($_POST['age'] >= 18)→"123px"转成123,通过校验 - 数组键名混用:
$arr["1"] = 'a'; $arr[1] = 'b';→ 实际只有一个键1,后者覆盖前者
怎么安全地替代 ==?
不能一刀切换 ===,得看场景。有些地方强制类型一致反而出错(比如 JSON 解析后数字可能是字符串):
- 明确要数值比较:先用
(int)或filter_var($val, FILTER_VALIDATE_INT)转换,再用=== - 字符串 ID 校验:统一用
===,但确保两边都是字符串(比如(string)$db_id === $_GET['id']) - 判断是否为数字内容:别信
is_numeric()(它认为"123abc"是数字),改用ctype_digit()(仅纯数字字符串)或正则/^\d+$/ - 涉及用户输入的比较(如登录、token),优先用
hash_equals()做恒定时长比较,避免时序攻击
特别注意:PHP 8.0 对 assert() 默认开启异常抛出,但弱类型比较本身不触发 assert,所以这类逻辑偏差不会被日志捕获,只能靠单元测试覆盖边界值。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











