strlen() 本就按字节计数,非 bug 而是设计;mb_strlen() 需确保 mbstring 扩展启用、显式传入正确编码(如 'UTF-8'),并统一字符串实际编码,否则结果不可靠。

strlen 本来就不该处理多字节字符
strlen() 的行为从 PHP 1.0 到 8.5.7 都没变过:它只数字节,不认字符。这不是 bug,是设计——官方文档明确写着 strlen() returns the number of bytes。你看到“你好”返回 6,是因为 UTF-8 下每个汉字占 3 字节,2 × 3 = 6。这不是版本问题,是函数职责问题。
mb_strlen 不生效?先查 mbstring 扩展是否真启用
PHP 8.5.7 默认仍不强制启用 mbstring,即使装了也可能被禁用。常见错误包括:
-
php.ini里extension=mbstring被注释或拼错(比如写成mb_string) - Docker 或云环境使用精简镜像(如
php:8.5.7-cli-alpine),根本没编译mbstring - 运行时用
php -m | grep mbstring查不到,但代码里又没加function_exists('mb_strlen')防御,直接 fatal error
验证方式:var_dump(function_exists('mb_strlen')); —— 返回 false 就得去配扩展,不是换函数能解决的。
编码参数漏写或写错,mb_strlen 也会“不准”
mb_strlen($str, 'UTF-8') 和 mb_strlen($str) 在 PHP 8.5.7 中行为可能不同,因为 mb_internal_encoding() 的默认值未必是 UTF-8(尤其老配置迁移过来的环境)。容易踩的坑:
立即学习“PHP免费学习笔记(深入)”;
- 传
'utf8'(少横线)→ PHP 不识别,退回到内部编码,结果不可控 - 字符串实际是
GBK编码,却硬传'UTF-8'→ 解析错乱,长度可能偏小甚至 false - 用户输入来自表单或 API,编码未统一(比如前端传 UTF-8,数据库连的是 latin1)→ 先转码再算:
mb_strlen(mb_convert_encoding($str, 'UTF-8', 'auto'), 'UTF-8')
替代方案:没 mbstring 时怎么安全计数
某些受限环境(如嵌入式 PHP、CI 构建机)确实没法开 mbstring。这时别硬套 strlen,可用:
-
preg_match_all('/./u', $str, $matches)——/u修饰符强制 UTF-8 模式,count($matches[0])是真实字符数 - 手动遍历 UTF-8 字节:检查
0xxxxxxx(单字节)、110xxxxx(双字节起始)、1110xxxx(三字节起始)等前缀,跳过后续字节 —— 但注意 emoji 可能占 4 字节(如?) - 用
iconv('UTF-8', 'UCS-4//IGNORE', $str)转成定长编码再除以 4 —— 前提是iconv扩展可用
真正麻烦的从来不是函数名,而是编码状态是否清晰、是否全程一致。一个 mb_strlen 调用背后,至少要确认三件事:扩展开着、字符串编码已知、参数编码匹配——缺一不可。



















