
用 str_ends_with() 最省心(PHP 8.0+)
PHP 8.0 起原生支持 str_ends_with(),它专为判断后缀设计,语义清晰、性能好、不区分大小写可选。比自己写 substr() 或正则更安全,也比 strpos() + strlen() 组合少出错。
- 直接传入字符串和后缀即可,返回
true或false - 第三个参数
$case_sensitive默认为true,想忽略大小写就显式传false - 后缀为空字符串
''时始终返回true,符合 RFC 与多数语言惯例 - 不会因多字节字符(如中文、emoji)出错——它内部用的是字节安全的逻辑,但注意:它按字节而非 Unicode 字符比较,对 UTF-8 字符串通常没问题;真要严格 Unicode 对齐得用
mb_substr()配合
// 示例
str_ends_with('report.pdf', '.pdf'); // true
str_ends_with('Image.JPG', '.jpg'); // false
str_ends_with('Image.JPG', '.jpg', false); // truePHP 7.x 怎么安全兼容?别用 substr() 硬切
很多人直接写 substr($str, -strlen($suffix)) === $suffix,看着短,但容易崩:
- 当
$str比$suffix还短时,substr($str, -strlen($suffix))返回false,导致恒为false(或触发 notice) - 中文、emoji 等多字节字符下,
strlen()返回字节数,而substr()的负偏移按字节算,可能截到字符中间,结果不可靠
更稳妥的做法是先长度检查,再用 substr_compare():
-
substr_compare()支持从末尾偏移,且第三个参数为0表示“比较到结尾”,天然适配后缀判断 - 它返回
0表示匹配,非0表示不匹配,不会因长度不足报错 - 可通过第四个参数控制是否区分大小写(
$case_insensitive = true)
function ends_with($str, $suffix, $case_insensitive = false) {
if (strlen($str) < strlen($suffix)) return false;
return substr_compare($str, $suffix, -strlen($suffix), strlen($suffix), $case_insensitive) === 0;
}为什么不用 preg_match() 写后缀判断?
正则确实能做,比如 preg_match('/.pdf$/i', $str),但没必要:
立即学习“PHP免费学习笔记(深入)”;
- 正则引擎启动开销大,尤其短字符串高频调用时,性能比
str_ends_with()差 3–5 倍 -
$在多行模式下可能匹配换行符前,行为不如字面后缀判断稳定 - 后缀含正则元字符(如
.、*、?)必须手动preg_quote(),漏了就逻辑错 - 错误信息难定位:
Warning: preg_match(): Compilation failed和业务逻辑无关,徒增排查成本
除非你在做动态后缀规则(比如从配置读正则模式),否则纯后缀判断请绕开正则。
注意 mb_* 函数不是万能解药
有人觉得“中文要用 mb_substr()”,于是写:
mb_substr($str, -mb_strlen($suffix)) === $suffix
这依然有问题:
-
mb_substr($str, -mb_strlen($suffix))在$str太短时返回空字符串,但空字符串和$suffix比较仍可能为false,没解决长度校验问题 -
mb_*函数依赖正确的mb_internal_encoding()设置,线上环境若没统一设成UTF-8,结果会随机错 - 多数真实场景中,文件名、URL、协议标识等后缀本身是 ASCII(如
.json、://),用mb_*反而引入额外开销和配置风险
真正需要 mb<em>*</em> 的情况极少,比如处理用户输入的带中文扩展名(报告.终稿.docx),且你确定所有环境编码一致——这种边缘 case,建议先转成标准 ASCII 后缀再判断,而不是强上 mb*。
判断字符串结尾这事,核心就两点:长度够不够、字节对不对齐。复杂点往往不在函数选型,而在没想清楚输入来源是否可控、编码是否混杂、错误分支有没有覆盖。











