直接用 serialize() 存数组最常导致字段截断、反序列化失败及跨语言不可读;json_encode() 虽跨语言友好,但不支持资源、闭包等非json类型,且对键名和特殊值敏感;数据库优先用 json_encode(),session 必须用 serialize()。

serialize() 保存数组时会出什么错
直接用 serialize() 存数组进数据库或缓存,最常踩的坑是:字段长度不够、反序列化失败、跨语言读取不了。它生成的字符串含 PHP 特有类型标识(比如 s:5:"hello"; 中的 s: 表示 string),一旦 PHP 版本升级或目标环境不是 PHP,unserialize() 很可能抛出 Notice: unserialize(): Error at offset。
- MySQL
TEXT类型够用,但TINYTEXT(最大 255 字节)极易截断,尤其数组嵌套深时 - 如果数组里有闭包、资源句柄(如
fopen()返回的 file pointer),serialize()会静默丢掉这些值,不报错但数据已失真 - 用
serialize()存的数据,Python/Node.js 拿到就是乱码,没法直接解析
json_encode() 替代 serialize() 的限制在哪
json_encode() 输出的是标准 JSON 字符串,跨语言友好,但对 PHP 数组结构很挑剔——它只认「可 JSON 化」的数据。遇到不可转译的内容,要么返回 false,要么静默跳过(取决于选项),而且不提示具体哪一项坏了。
- 数组键名必须是字符串或整数;含中文键、空格键、点号键(如
"user.name")会被转成对象属性,反解回 PHP 时变成stdClass而非关联数组 - 值里有
NaN、INF、-INF,json_encode()直接返回false;PHP 7.3+ 加JSON_INVALID_UTF8_IGNORE才能跳过非法 UTF-8 字节,否则整个失败 - 资源、闭包、
DOMDocument等对象,一律被转成null,且不警告
怎么选:存数据库用 json_encode,存 Session 用 serialize
这不是教条,是权衡结果。Session 默认用 serialize(),因为 PHP 内部要精确还原对象实例、私有属性、类名等;而数据库字段本质是字符串容器,JSON 更安全、可读、易调试。
- 写 MySQL 或 Redis 字符串值:优先
json_encode($arr, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),避免中文转义、URL 斜杠双转义 - 存进
$_SESSION或需要保持对象完整性的场景:坚持用serialize(),别自己换 - 如果数组里有
DateTime对象,json_encode()默认只输出时间戳字符串,想保留格式得提前format()成字符串,或用JsonSerializable接口定制
反序列化时最容易漏掉的校验点
无论用哪个函数存,读出来那一刻才是风险高发期。很多人直接 unserialize() 或 json_decode(),没检查返回值是否有效,导致后续逻辑崩在奇怪位置。
立即学习“PHP免费学习笔记(深入)”;
-
unserialize()前先用is_string($data) && strlen($data) > 0过滤空值;再加@抑制警告,配合!=== false判定是否成功(注意:PHP 8.1+ 对恶意 payload 有更严格检测,可能抛 Exception) -
json_decode($str, true)必须检查返回值是否为null,然后用json_last_error() === JSON_ERROR_NONE确认无错;若$str来自用户输入,还要防空字节注入(\x00)导致截断 - 从数据库读出 JSON 字符串后,别直接
json_decode()—— 先trim()去首尾空白,MySQL 有时会悄悄补空格
json_encode,又没实现 Serializable 接口。











