必须显式传入'UTF-8',因mb_strlen()默认依赖mb_internal_encoding()值(可能为ISO-8859-1或空),导致中文返回0或1;不校验类型和编码易出错,需用safe_mb_strlen等封装函数。

PHP 默认的 strlen() 函数按字节计数,遇到 UTF-8 编码的中文会把一个汉字算作 3 个字节,导致长度判断错误。要准确判断中文字符串长度,必须用 mb_strlen(),且必须显式指定编码。
为什么 mb_strlen() 不传 $encoding 参数会出错
PHP 的 mb_strlen() 默认使用 mb_internal_encoding() 的值作为编码,而该值在未手动设置时可能为 ISO-8859-1 或空,导致中文被截断或返回 false。常见现象是:明明有 5 个汉字,却返回 0 或 1。
- 始终显式传入
'UTF-8',不要依赖默认值 - 检查脚本开头是否调用了
mb_internal_encoding('UTF-8')—— 这只是设置内部编码,不改变mb_strlen()的行为逻辑 - Web 环境下,即使 HTML 声明了
charset=utf-8,PHP 仍不会自动将mb_strlen()的默认编码设为 UTF-8
mb_strlen() 和 strlen() 混用的典型翻车场景
用户输入校验、数据库字段长度限制、JSON 返回截断等场景最容易出问题。例如表单要求「昵称不超过 10 个字符」,用 strlen() 判定「你好世界」会得到 12,误判超长;而用 mb_strlen($str, 'UTF-8') 才得 4。
- 数据库字段如
VARCHAR(20)是按字符计(MySQL 5.5.3+ utf8mb4),和mb_strlen()对齐,不是strlen() -
前端 JS 的
.length是按 Unicode 字符计,和mb_strlen($s, 'UTF-8')行为一致,前后端校验才能对齐 - 注意 emoji 和生僻汉字(如「?」)在 UTF-8 中占 4 字节,
mb_strlen()仍计为 1,符合预期;但substr()必须换用mb_substr(),否则会乱码
如何安全地封装一个防错的中文长度判断函数
直接裸用 mb_strlen() 仍有风险:比如传入 null、数组、资源类型时会警告;或者字符串本身不是合法 UTF-8(如 GBK 混入),mb_strlen() 可能返回异常值。
立即学习“PHP免费学习笔记(深入)”;
- 加类型判断:
is_string($str) && $str !== '' - 用
mb_check_encoding($str, 'UTF-8')预检编码,非 UTF-8 可考虑转码或拒绝 - 示例:
function safe_mb_strlen($str) {
if (!is_string($str)) return 0;
if (!mb_check_encoding($str, 'UTF-8')) return 0;
return mb_strlen($str, 'UTF-8');
}
这个函数在 API 入参校验、ORM 属性赋值前调用,比到处写 mb_strlen($x, 'UTF-8') 更可靠。
真正容易被忽略的是:PHP-FPM 或 CLI 环境下,mbstring.func_overload 如果开启(已废弃但仍有遗留配置),会让 strlen() 自动变成 mb_strlen() —— 表面正常,实则掩盖了编码不一致隐患。查 phpinfo() 或 ini_get('mbstring.func_overload'),确保它为 0。











