php字符串底层将字符串视为带长度的字节序列,存储指针val和长度len,支持含\0的二进制数据;单字节函数按字节操作,多字节函数(如mb_strlen)需指定编码按字符处理,混用易导致截断或乱码。

PHP字符串底层实现的核心,是它把字符串当作带长度的字节序列来管理,而不是C语言那种以\0结尾的“空终止字符串”。
这意味着:
- 每个PHP字符串在内存中明确存有两样东西:指向字节数组的指针
char *val,以及独立记录的长度int len; - 它天然支持包含
\0、控制字符、任意二进制数据,不会被意外截断; - 所有字符串操作(如
strlen,substr)都基于这个长度值,而非扫描到\0为止。
举个例子:
$str = "a\x00b"; var_dump(strlen($str)); // 输出 int(3),不是2 —— 因为长度是显式存储的
PHP中二进制字符串与Unicode字符串的本质区别
关键不在“字符串类型”,而在于如何解释字节序列。
-
二进制字符串:就是原始字节流,不预设任何字符含义。比如
pack("H*", "c3b1")得到的两个字节0xc3 0xb1,本身只是数值,没说是字符还是图像头; -
Unicode字符串(如UTF-8编码):是按特定规则把Unicode码点映射成字节序列的结果。例如字符
ñ(U+00F1)在UTF-8中恰好编码为0xc3 0xb1—— 同样的两个字节,加上“这是UTF-8”的上下文,才具备语义。
所以差异本质是:
- 二进制字符串关注字节内容和长度;
- Unicode字符串关注字符意义和编码规则。
单字节函数 vs 多字节函数:为什么不能混用?
PHP默认的字符串函数(strlen, substr, strpos 等)全部按字节操作:
-
strlen("中国")返回6(UTF-8下每个汉字占3字节); -
substr("中国", 0, 4)截出"中"—— 第4个字节落在第二个汉字中间,破坏了UTF-8编码结构。
而 mb_* 函数(需启用 mbstring 扩展)会:
- 先识别编码(如
'UTF-8'); - 再按字符单位解析字节流,跳过多字节字符边界;
-
mb_strlen("中国", 'UTF-8')返回2; -
mb_substr("中国", 0, 1, 'UTF-8')正确返回"中"。
实际开发中要注意什么?
- ✅ 存储/传输时,字符串就是字节流 —— 用
file_get_contents()读图片、用pack()构造协议包,都依赖其二进制安全特性; - ✅ 显示或处理文本时,必须明确指定编码,并优先使用
mb_*函数; - ✅ 接收用户输入(如表单、URL参数)时,检查
mb_check_encoding($str, 'UTF-8')防止无效编码导致截断或漏洞; - ❌ 不要用
strlen判断中文昵称是否超长,也不要用strpos查找emoji(可能跨4字节); - ❌ 不要在未声明编码的情况下调用
mb_internal_encoding(),否则mb_*函数行为不可控。
不复杂但容易忽略。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











