mb_strlen() 是唯一靠谱的多字节字符串长度函数,它按字符(code point)而非字节计数,需显式指定编码如 'UTF-8',否则可能退化为字节计数;处理 emoji 或组合字符应改用 grapheme_strlen() 获取视觉长度。

mb_strlen() 是唯一靠谱的多字节字符串长度函数
PHP 默认的 strlen() 只按字节计数,对中文、日文、emoji 等会严重误判。比如 "你好" 在 UTF-8 下占 6 字节,strlen() 返回 6,但语义长度是 2。mb_strlen() 才真正按字符(code point)计算,前提是明确指定编码。
实操要点:
- 必须传入第二个参数,如
mb_strlen($str, 'UTF-8');不传时依赖mb_internal_encoding(),极易出错 - 编码名必须准确:用
'UTF-8',不是'utf8'或'utf-8'(PHP 对大小写敏感,且不接受短横线) - 若字符串编码未知,先用
mb_detect_encoding($str, ['UTF-8', 'GB2312', 'BIG5'], true)探测,但该函数不可靠,优先保证输入源统一为 UTF-8
处理 emoji 和组合字符要额外小心
某些 emoji(如 ??)或带变音符号的字符(如 é)在 UTF-8 中由多个 Unicode 码点组成,mb_strlen() 默认按码点计,结果可能不符合视觉预期。例如 "??" 由 4 个码点组成(ZJW + MAN + ZWJ + COMPUTER),mb_strlen() 返回 4,但人眼只认作 1 个“字符”。
若需视觉长度(grapheme cluster 长度),改用 grapheme_strlen():
立即学习“PHP免费学习笔记(深入)”;
$str = "Hello ??";
echo mb_strlen($str, 'UTF-8'); // 输出 9
echo grapheme_strlen($str); // 输出 8(更贴近显示宽度)
注意:grapheme_strlen() 依赖 intl 扩展,线上环境需确认已启用。
替代方案:substr() 和 mb_substr() 切片必须配套使用
长度判断和截断必须用同一套逻辑,否则索引错位。用 strlen() 判断长度却用 mb_substr() 截取,大概率乱码或截半字符。
正确做法:
- 统一用
mb_strlen()判断长度 - 统一用
mb_substr($str, $start, $length, 'UTF-8')截取,第三个参数是字符数,不是字节数 - 避免混用
substr()/mb_substr(),尤其当字符串含中文或 emoji 时
性能差异小,但编码缺失会导致静默错误
mb_strlen() 比 strlen() 略慢(因需解析多字节序列),但在绝大多数 Web 场景中可忽略。真正的风险在于漏写编码参数——它不会报错,只是退化成类似 strlen() 的行为,问题在线上才暴露,且难以复现。
建议在项目初始化处强制设置:mb_internal_encoding('UTF-8');,再全局使用无编码参数的 mb_strlen($str)。但更推荐显式传参,避免依赖全局状态。
最易被忽略的是:数据库连接、HTTP 请求头、文件读取等环节若未统一 UTF-8,mb_strlen() 再准也救不了源头乱码。











