PHP 8.3 中 strlen() 返回字节数而非字符数,UTF-8 下中文占3字节,如 strlen("你好")=6;应改用 mb_strlen($str, 'UTF-8') 获取真实字符数。

PHP 8.3 中判断字符串长度,表面看只是调用一个函数的事,但实际踩坑点不少,尤其在处理中文、emoji、混合编码或用户输入时。核心问题不在版本本身新增了什么限制,而在于旧习惯与新环境的不兼容——比如仍用 strlen() 做字符数校验,或忽略编码参数导致 mb_strlen() 返回意外结果。
坑一:用 strlen() 当“字符数”用,中文直接翻三倍
strlen() 在 PHP 8.3 里依然只返回字节数,且行为完全向后兼容。UTF-8 下一个中文字符占 3 字节,strlen("你好") 就是 6,不是 2。表单限制“最多 10 个字符”,用户输 4 个汉字就超限;密码策略写 strlen($pwd) ,结果用户设 “?野家”(含 4 字节 emoji)可能被误判过短。
- 永远别用
strlen()判断用户可见的“字符个数” - 纯英文/数字场景可临时用,但项目一旦支持多语言,就得统一替换
- PHP 8.3 不会警告你用错了,它安静地返回错误数字
坑二:mb_strlen() 不传编码参数,结果依赖运行时配置
mb_strlen($str) 看似简洁,但省略第二个参数时,它会读取 mb_internal_encoding() 的当前值。这个值可能被框架、中间件甚至某段老代码悄悄改过,也可能在 CLI 和 Web SAPI 下不一致。
PHP 8.5.12 RC 1 候选版修复 BZ2、DOM、PDO、Opcache/JIT 和扩展内存安全问题,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- 常见表现:本地开发输出 4,线上服务器输出 12(因为内部编码被设成 ISO-8859-1)
- PHP 8.3 不强制要求传编码,也不报错,但结果不可控
- 正确写法始终显式指定:
mb_strlen($str, 'UTF-8')
坑三:遇到 emoji 或生僻汉字,普通 mb_strlen 仍不准
UTF-8 中,部分 emoji(如 ??)或扩展汉字(如 “?”)属于 Unicode 超过 3 字节的码点,需 4 字节存储。更关键的是,它们可能由多个 Unicode 码点组合而成(如带肤色修饰符的 ???),这时“字符数”取决于你定义的单位:
立即学习“PHP免费学习笔记(深入)”;
-
mb_strlen($str, 'UTF-8')按码点(code point)计数,“???”算 4 个(基础 + 修饰符 + 连接符) - 若需按人眼看到的“图形单元”(grapheme cluster)计数,得用
grapheme_strlen($str) - PHP 8.3 已内置
grapheme_strlen(),无需额外扩展,但很多人根本不知道它的存在
坑四:非字符串类型传入,PHP 8.3 开始更严格报错
PHP 8.3 延续并强化了类型安全趋势。向 strlen() 或 mb_strlen() 传数组、null、对象等非字符串值,不再容忍隐式转换:
- 传
null→ 触发TypeError(不再是静默转为空字符串) - 传数组 → 直接抛出
TypeError,不会像旧版那样返回 int(5) - 安全做法:校验类型再计算,例如
is_string($input) ? mb_strlen($input, 'UTF-8') : 0


















