DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

PHP 用 strpos 大于等于 0 判断包含关系,未找到字符串也进入分支

strpos 返回整数位置或 false,非严格比较会让未找到也通过。用 !== false 保留位置 0 的有效匹配,并明确空输入和 PHP 版本条件。

目标字符串明明不存在,strpos($text, $needle) >= 0 却仍然为真。把判断改成 if (strpos(...)) 后,又会漏掉位于开头的匹配。这两个现象来自返回值的不同类型:找到时是整数位置,找不到时是布尔值 false。

以下判断适用于 PHP 7 和 PHP 8,搜索词按非空字符串处理。PHP 8 还可以使用返回布尔值的 str_contains()。

用返回类型区分未找到和第一个位置

先在开发环境观察返回值,避免只用字符串拼接打印它:

<?php
var_dump(strpos('debug wiki', 'debug'));
var_dump(strpos('debug wiki', 'wiki'));
var_dump(strpos('debug wiki', 'missing'));

预期依次是 int(0)、int(6)、bool(false)。第一个位置从 0 开始,因此 0 是有效结果。

>= 会进行非严格比较。在 false >= 0 中,布尔值与另一类型比较时,两边按布尔值比较;0 转为 false,所以这个表达式为真。直接把返回值放进条件也不合适,因为整数 0 在布尔上下文中为假。

只把严格等于 false 当作未找到

需要位置时保存返回值,然后严格判断:

<?php
$text = 'debug wiki';
$needle = 'debug';

if ($needle === '') {
    throw new InvalidArgumentException('Search term must not be empty');
}

$position = strpos($text, $needle);
if ($position !== false) {
    echo 'Found at position ' . $position . PHP_EOL;
} else {
    echo 'Not found' . PHP_EOL;
}

示例预期输出 Found at position 0。搜索词换成 wiki 应显示位置 6,换成 missing 应进入未找到分支。严格比较检查类型和值,能区分整数 0 与布尔值 false。

空搜索词的处理应由业务约定决定。这里明确拒绝空字符串,避免空输入被当作有意义的命中;PHP 8 的 strpos() 允许空 needle,旧版行为不能直接照搬。

PHP 8 只判断存在时可使用 str_contains

不需要位置时,可以直接取得布尔结果:

<?php
$text = 'debug wiki';
$needle = 'wiki';

if ($needle !== '' && str_contains($text, $needle)) {
    echo 'Found' . PHP_EOL;
} else {
    echo 'Not found' . PHP_EOL;
}

str_contains() 区分大小写,空搜索词总是匹配,所以示例仍保留非空检查。PHP 7 没有这个函数;需要兼容 PHP 7 时沿用 strpos(...) !== false。

如果原业务会先把两边转换成小写,不要在修复返回值判断时顺手取消这个步骤,否则搜索语义也会改变。大小写、编码和返回类型是不同问题,应分别验证。

修改后至少覆盖开头命中、中间命中、完全未命中和空输入四种情况,并核对当前业务对大小写的要求。这次修复只需改条件表达式;保留原代码以便回退,但不要通过重写数据或放宽权限掩盖判断错误。