strlen() 返回字节数而非字符数,如"你好"返回6;处理UTF-8多字节字符应改用mb_strlen($str, 'UTF-8'),并确保mbstring扩展启用且显式指定编码。

strlen() 返回的是字节数,不是字符数。处理中文、emoji 或其他 UTF-8 多字节字符时,直接用它会严重高估“长度”——比如 "你好" 在 UTF-8 下返回 6,但你真正想校验的往往是“2个字符”,这时候必须换函数。
为什么 strlen("你好") 返回 6 而不是 2
因为 strlen() 完全不解析编码,只数内存里的字节:UTF-8 中每个汉字占 3 字节,两个就是 6。它对空格、制表符、换行符("\n")、甚至二进制数据都一视同仁地按字节计数。
常见错误现象:
- 表单提交中文标题被数据库
VARCHAR(20)截断——strlen()判定“15 字节”放得下,实际存了 5 个汉字(15 字节),但业务逻辑本意是“最多 20 个字符” - 前端 JS 用
.length(按字符)校验,后端 PHP 用strlen()(按字节)校验,结果不一致导致拦截失败
使用场景:仅适合纯 ASCII 场景(如 token、base64 字符串、HTTP 头字段值、日志行原始字节数统计)。
立即学习“PHP免费学习笔记(深入)”;
mb_strlen() 是更安全的默认选择
只要你的项目支持 UTF-8(现代 PHP 项目基本都支持),mb_strlen() 应该成为获取“人类可读长度”的首选。它需要 mbstring 扩展启用,且强烈建议显式传入编码参数,避免依赖 mb_internal_encoding() 的全局设置。
实操建议:
- 检查扩展是否启用:
extension=mbstring在php.ini中已取消注释,重启 Web 服务后运行php -m | grep mbstring - 始终显式指定编码:
mb_strlen($str, 'UTF-8'),不要省略第二个参数 - 如果字符串来源不可控(如用户上传的文件名、第三方 API 响应),先用
mb_detect_encoding()粗略判断再传参,或统一转成 UTF-8 再计算 - 注意:
mb_strlen()对 ASCII 字符串结果和strlen()一致,可无痛替换
PHP 8.1+ 对非字符串参数更严格
传数组、null、对象给 strlen() 在 PHP 8.1+ 会触发 E_DEPRECATED 警告,并可能在后续版本报错。这不是小问题——尤其在动态拼接变量时容易踩中。
典型翻车点:
-
strlen($_GET['name'] ?? '')看似安全,但如果$_GET['name']是数组(如 URL 中传了?name[]=a&name[]=b),PHP 8.1+ 会警告 -
strlen($user->getName()),而getName()有时返回null或对象(未实现__toString)
稳妥写法是提前类型断言:strlen((string) $value) 或用 is_string($value) ? strlen($value) : 0。
性能差异其实可以忽略
有人担心 mb_strlen() 比 strlen() 慢。PHP 7+ 已优化其底层实现,对纯 ASCII 字符串,两者耗时几乎无差别;对含中文的字符串,多出的开销是合理代价——毕竟你本来就需要正确语义。
真正要警惕的是混用:
- 数据库字段定义为
VARCHAR(50)(字符数),却用strlen()做前置校验 → 插入失败或截断 - JS 前端用
text.length显示剩余字数,后端用strlen()校验 → 用户看到“还剩 10 字”,输到第 4 个汉字就被拦住
复杂点在于:同一个字符串,在不同环节可能被不同方式解释(字节流、字符序列、图形符号 unit)。别假设“长度”是个绝对概念——它永远依赖上下文。



















