mb_substr 和 substr 结果不同,根本原因是前者按字符截取、后者按字节截取;处理 UTF-8 多字节字符(如中文、emoji)时,substr 可能截断字符导致乱码,而 mb_substr 能正确解析编码并安全截取。

mb_substr 和 substr 在 PHP 7.4(以及所有支持多字节的 PHP 版本)中结果不同,根本原因在于:它们操作的单位完全不同——一个是字符(character),一个是字节(byte)。尤其在处理中文、日文、emoji 等 UTF-8 多字节字符时,这个差异会直接导致截取内容错乱或长度误判。
substr() 是字节级截取
它不识别编码结构,只是从字符串内存位置开始,按字节数硬切:
- UTF-8 中,一个中文占 3 字节,一个 emoji(如 ?)可能占 4 字节;
-
substr($str, 0, 5)表示“取前 5 个字节”,不管这 5 字节是否落在某个中文字符中间; - 若恰好切在“你好”的第 2 字节处,就会得到
"你"这类乱码。
$str = "你好world"; echo substr($str, 0, 5); // 输出:"你好w"?错!实际是:"你"(3字节) + "wo"(2字节)→ 显示为 "你wo" 或类似乱码 echo strlen(substr($str, 0, 5)); // 输出 5(字节数),但只含 2 个完整字符
mb_substr() 是字符级截取
它依赖 mbstring 扩展,能解析 UTF-8 的变长编码规则,把字节流正确还原为逻辑字符再操作:
-
mb_substr($str, 0, 5, 'UTF-8')表示“取前 5 个字符”,无论每个字符占几个字节; - 自动跳过非法字节偏移,确保不会截断半个汉字;
- 返回结果语义清晰,
mb_strlen()测得的长度也与预期一致。
$str = "你好world"; echo mb_substr($str, 0, 5, 'UTF-8'); // 输出:"你好wor"(2 中文 + 3 英文 = 5 字符) echo mb_strlen(mb_substr($str, 0, 5, 'UTF-8'), 'UTF-8'); // 输出 5
关键区别总结
-
substr()- 不检查编码,纯字节偏移;
- 快(无解析开销),但危险;
- 仅适合纯 ASCII 场景(如英文 ID、数字、URL path 段)。
-
mb_substr()- 需显式指定编码(推荐
'UTF-8'); - 依赖
mbstring扩展(PHP 7.4 默认启用,但需确认php.ini中未禁用); - 安全、可预测,是处理用户输入、多语言内容的唯一合理选择。
- 需显式指定编码(推荐
常见踩坑点
- 忘记传第 4 个参数
'UTF-8',导致使用默认内部编码(可能为ISO-8859-1),中文仍乱码; - 混用
strlen()和mb_substr():strlen()返回字节数,不能代表“有几个字”; - 用
substr()截取后做mb_strlen()判断——输入已是乱码,结果无意义。
不复杂但容易忽略
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











