JSON缓存读出null而serialize()正常,因json_encode()丢弃DateTime、闭包等非标量类型,序列化失败写入空字符串;serialize()保留完整PHP类型但依赖类加载。

为什么 JSON 缓存读出来是 null,而 serialize() 能正常取到?
根本原因是 PHP 原生序列化能保留类型(如 array、object、resource),而 json_encode() 会丢弃非标量类型和部分结构信息。比如缓存一个含 DateTime 对象或闭包的数组,json_encode() 直接返回 false,写入缓存的就是空字符串,读取时 json_decode() 得到 null。
- 常见错误现象:
Cache::get('key')返回null,但确认写入过且未过期 - 检查方法:用
file_get_contents()直接读缓存文件内容,看是不是空或非法 JSON -
JSON方式不支持resource、closure、私有/受保护属性(除非实现JsonSerializable) - ThinkPHP 默认缓存驱动(如
File、Redis)若配置'serialize' => 'json',就走这一套
serialize() 和 json_encode() 在 ThinkPHP 缓存配置里怎么选?
看数据是否跨语言、是否含复杂结构。如果只是 PHP 内部使用、可能存对象或带方法的类实例,必须用 serialize();如果缓存数据要被 Node.js 或 Python 读,或只存简单键值(string/int/array),优先用 json。
- 配置位置:
config/cache.php中的'default' => ['serialize' => 'php']或'serialize' => 'json' -
'serialize' => 'php'实际调用serialize()/unserialize(),兼容所有 PHP 类型 -
'serialize' => 'json'对应json_encode()/json_decode($data, true),强制转成关联数组,丢失对象行为 - Redis 场景下,
json序列化后体积更小、可读性略好,但反序列化性能略低于php方式
自定义缓存序列化方式时,unserialize() 报 Class not found 怎么办?
这是 serialize() 的典型副作用:它把类名完整写进字符串,反序列化时若类未加载,就会失败。不是缓存坏了,是环境缺失依赖。
- 错误信息示例:
unserialize(): Error at offset 0 of 123 bytes或更明确的Class 'App\Model\User' not found - 解决前提是确保反序列化前已
require或自动加载对应类(如通过 Composer autoload) - ThinkPHP 中建议在
app/common.php或服务提供者里提前引入关键模型类 - 避免缓存未定义类的实例——比如开发时用了匿名类或临时
new class {},上线后必炸
Redis + json 序列化时,Cache::remember() 回调函数返回对象却存成了 null
因为 Cache::remember() 底层先执行回调,再尝试序列化结果。如果回调返回的是对象且没实现 JsonSerializable,json_encode() 失败,整个缓存写入就静默失败(ThinkPHP 不抛异常,只写空值)。
- 典型场景:回调里
return User::find(1),User是 Eloquent 模型,未实现JsonSerializable - 验证方法:在回调末尾加
var_dump(json_encode($result));,看是否为false - 安全做法:显式转数组,例如
return User::find(1)->toArray(); - 或者改用
'serialize' => 'php',但需接受无法跨语言、且反序列化风险
ThinkPHP 缓存序列化的坑不在“会不会配”,而在“有没有意识到数据结构和序列化能力之间的契约”——一旦打破,表现就是悄无声息的 null 或 unserialize() 报错,排查时容易绕远路。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










