PHP7中用strpos模拟str_contains需严格比较!== false,注意空字符串、大小写敏感(用stripos)、参数类型检查及UTF-8安全,推荐优先使用Symfony String等成熟库。

PHP7 里用 strpos 模拟 str_contains
PHP8 的 str_contains 是个纯布尔函数,只关心“有没有”,不关心“在哪”。PHP7 最直接的替代就是 strpos,但必须注意返回值类型和假值陷阱:strpos 找到开头位置时返回 0,而 0 == false 会误判为“不存在”。
正确写法是用严格比较:
if (strpos($haystack, $needle) !== false) { ... }
- 别用
!= false或== true,它们在$needle在开头时出错 -
$haystack和$needle都要确保是字符串,否则strpos可能静默转成空字符串或触发警告 - 如果
$needle为空字符串,strpos返回0(PHP7.4+),逻辑上符合“包含”,但业务中通常要提前过滤空串避免歧义
需要大小写不敏感?用 stripos 而不是 strtolower + strpos
很多人第一反应是先转小写再查,比如 strpos(strtolower($haystack), strtolower($needle))。这看似直观,但有两处硬伤:一是多一次全量字符串拷贝,性能差;二是对多字节字符(如中文、emoji)可能出错,因为 strtolower 不保证 UTF-8 安全。
更稳妥的做法是直接用 PHP 内置的 stripos:
立即学习“PHP免费学习笔记(深入)”;
if (stripos($haystack, $needle) !== false) { ... }
-
stripos和strpos行为一致,同样要严格判断!== false - 它原生支持 UTF-8(只要系统 locale 或 mbstring 扩展就位),无需额外处理编码
- 如果项目已启用
mbstring,且明确要求多字节安全,可用mb_stripos($haystack, $needle, 0, 'UTF-8') !== false,但多数场景stripos足够
封装成兼容函数时,别忽略 null 和非字符串输入
如果想在项目里全局替换 str_contains,自己写一个 polyfill 函数,光处理逻辑不够,还得防御性检查参数类型。PHP7 下传入 null 或数组给 strpos 会触发 warning,而 PHP8 的 str_contains 对非字符串会直接报 TypeError。
建议这样写:
function str_contains($haystack, $needle) {
if (!is_string($haystack) || !is_string($needle)) {
return false;
}
return strpos($haystack, $needle) !== false;
}
- 返回
false比抛异常更贴近老环境习惯,也避免打断流程 - 不模仿 PHP8 的严格报错行为,除非你确定所有调用方都已适配
- 如果项目用了 strict types,记得在文件头加
declare(strict_types=1);,否则类型提示不会生效
第三方库或框架里已有现成方案?优先复用
不少现代 PHP 库(如 Symfony String、Laravel Support)早就提供了跨版本的字符串工具。例如 Symfony 的 String 组件:
use Symfony\Component\String\UnicodeString; (new UnicodeString($haystack))->contains($needle);
这类方案优点是开箱即用、测试充分、自动处理边界情况;缺点是引入依赖。是否采用取决于项目现状:
- 已用 Composer 且无依赖洁癖 → 直接 require
symfony/string,最省心 - 纯脚本或极简环境 → 手写
strpos判断更轻量 - 正在升级到 PHP8 → 建议只做最小兼容,别过早抽象,等升级完成就删掉 polyfill
真正容易被忽略的是:不同环境对空字符串、全角/半角、不可见字符(如零宽空格)的处理差异。哪怕逻辑上“包含”,实际渲染或存储时可能因编码或截断表现不一致——这种问题不会报错,但线上排查起来特别费时间。



















