首选 mb_substr() 截取 utf-8 字符串开头字符,需显式指定 'utf-8' 编码;substr() 仅适用于单字节编码,否则中文会乱码。

用 substr() 截取字符串开头最直接
PHP 里截取前几位字符,substr() 是首选,它原生支持从开头起取子串,语义清晰、兼容性好(5.0+ 都行)。别被名字误导——它不只“截中间”,负偏移才麻烦,正数起始点 + 正长度就是你要的“开头几位”。
常见错误是写成 substr($str, 0, -3) 想取前三位,结果截掉了末尾三字;或者漏写第三个参数,变成从位置 0 一直取到末尾。
-
substr($str, 0, 3):安全取前 3 个字符(含中文、emoji,前提是源字符串是 UTF-8 编码) - 如果字符串可能短于目标长度(比如取前 5 位但字符串只有 2 字),
substr()不报错,返回原串——这是预期行为,不用额外判断长度 - 注意:
substr()按字节操作,若字符串含多字节字符(如中文 UTF-8),且你传入的长度是“字符数”而非“字节数”,结果会乱码;此时应换用mb_substr()
中文/UTF-8 字符串必须用 mb_substr()
绝大多数现代 PHP 项目默认用 UTF-8,而中文一个字占 3 字节。substr() 数的是字节,mb_substr() 才数字符。用错就容易切在汉字中间,显示 或其他乱码。
典型现象:substr("你好世界", 0, 2) 返回空或乱码,因为前 2 字节不是完整字符;而 mb_substr("你好世界", 0, 2, 'UTF-8') 稳稳输出“你好”。
立即学习“PHP免费学习笔记(深入)”;
- 必须显式指定编码,如
'UTF-8';不传第四个参数时,依赖mb_internal_encoding()设置,容易出隐性问题 - 如果项目已全局设了
mb_internal_encoding('UTF-8'),第四个参数可省,但显式写上更可靠 - 性能略低于
substr(),但对几百字符以内的常规场景无感知
遇到空字符串或 null 时,substr() 和 mb_substr() 行为一致
两者对空字符串 ""、null、false 的处理相同:返回 false(注意不是空字符串)。这会导致 if 判断意外失败,比如 if (substr($str, 0, 1)) { ... } 在 $str 为空时跳过逻辑。
- 稳妥做法是先过滤:用
is_string($str) && $str !== ''判空,再调用截取函数 - 也可用空合并:
$first = $str ? mb_substr($str, 0, 1, 'UTF-8') : '' - 别依赖
@抑制警告——mb_substr(null, ...)触发 Warning,但@掩盖问题,不如提前检查
别用 str_split() + array_slice() 模拟截取
有人想“先把字符串拆成数组,再取前几个”,写成 implode('', array_slice(str_split($str), 0, 3))。这看似直观,实际有三个硬伤:
-
str_split()默认按字节拆分,中文照样乱码;加第二个参数1也解决不了 UTF-8 多字节问题 - 内存开销大:长字符串会生成巨大数组,比直接
mb_substr()多几倍内存占用 - 执行慢:拆分 + 切片 + 拼接,三步操作,基准测试下比
mb_substr()慢 3–5 倍
这种写法只适合极特殊场景(比如你要对每个字符做复杂判断),日常截开头,就老实用 mb_substr()。











