应使用 mb_strlen($str, 'UTF-8') 替代 strlen() 计算 emoji 字符数,对 ZWJ 合成序列等复杂情况则需 graphemestrlen();所有 mb* 操作须统一编码参数,避免混用导致错位。

PHP 默认的 strlen() 会把一个 emoji 算作多个字节(比如 ? 是 4 字节),导致“长度”和肉眼看到的字符数严重不符。要得到用户感知的「字符个数」,必须用多字节安全的方式处理。
用 mb_strlen() 替代 strlen()
这是最直接有效的解法,前提是字符串编码是 UTF-8(现代 PHP 项目基本都是):
-
mb_strlen($str, 'UTF-8')按 Unicode 字符计数,一个 emoji 算 1 - 务必显式传入
'UTF-8'第二个参数,否则依赖mb_internal_encoding()设置,容易出错 - 如果字符串可能含 GBK/Big5 等编码(如旧系统接口返回),先
mb_convert_encoding($str, 'UTF-8', 'AUTO')转码再计算
注意 mb_substr() 和截断逻辑一致性
判断长度只是第一步,后续常需截断、拼接等操作。若用 strlen() 判断长度,却用 mb_substr() 截取,结果会错位:
- 错误示例:
if (strlen($str) > 20) $short = mb_substr($str, 0, 20);—— 前者按字节算,后者按字符算,临界点不一致 - 统一用
mb_*函数族:if (mb_strlen($str, 'UTF-8') > 20) $short = mb_substr($str, 0, 20, 'UTF-8'); - 特别注意:
mb_substr()第四个参数必须和mb_strlen()保持一致,否则在非 UTF-8 编码下行为不可控
emoji 可能触发的隐藏问题:ZWNJ、ZWJ 序列
像 ??(程序员 emoji)这类合成 emoji,本质是多个 Unicode 码点 + 连接符(U+200D)组成。mb_strlen() 仍会返回 3 或 4,而非视觉上的 1:
立即学习“PHP免费学习笔记(深入)”;
- 纯显示计数需求(如限制输入框最大字符数),
mb_strlen()已足够 - 若需严格按「用户看到的图形数量」统计(如评论字数展示),得用更重的方案,比如
grapheme_strlen()(需启用 intl 扩展) -
grapheme_strlen($str)能正确识别 emoji ZWJ 序列、变体选择符(VS16)等,返回真实视觉字符数 - 但性能略低,且
intl扩展并非 PHP 默认开启,上线前需确认环境支持
真正麻烦的不是单个 emoji,而是混合了普通中文、英文、带修饰符的 emoji(如 ??)、ZWJ 合成序列的字符串——这时候只靠 mb_* 函数不够稳,grapheme_* 才是底线。别在没测过真实用户输入的情况下,假设「emoji 就是单个字符」。











