tp6缓存序列化报错本质是php serialize()遇closure、pdo等不可序列化类型中止,修复关键为提前识别并安全降级;应优先用json序列化替代,或自定义file驱动过滤危险类型,从业务层禁用高危写法。

TP6缓存驱动序列化报错,本质是 PHP 原生 serialize() 遇到不可序列化类型(如 Closure、PDO、resource)时直接中止,不是配置错,而是数据本身越界。修复关键在于“不硬塞”,而要提前识别、安全降级。
识别典型报错和触发场景
常见错误提示包括:
- Serialization of 'Closure' is not allowed
- Exception: Serialization of 'PDO' is not allowed
- Serialization of 'mysqli' is not allowed
这些几乎都源于把不该缓存的对象直接传给了 Cache::set() 或 S(),例如:
- 缓存整个
Request或Response对象 - 缓存含匿名函数的配置数组:
['handler' => function() {}] - 第三方 SDK 返回的 client 实例(如微信支付
PayClient)未做剥离就写入缓存
优先用 JSON 序列化替代 serialize
Redis 和 Memcached 驱动支持 serialize 配置项,设为 'json' 可绕过 PHP 原生限制,自动跳过不可序列化值并转为 null:
- 在
config/cache.php的 Redis store 中添加:'serialize' => 'json' - JSON 方式天然拒绝对象、资源、闭包,只保留标量、数组、stdClass 等可表达结构
- 注意:若业务依赖对象的
__sleep()行为(如自定义序列化字段),需评估兼容性
自定义 File 驱动实现安全序列化
若仍需使用文件缓存(如无 Redis 环境),可扩展 File 驱动,在序列化前过滤危险类型:
- 新建
app/common/cache/SerializableFile.php,继承think\cache\driver\File - 重写
serialize()方法:对is_object()或is_resource()的值统一转为null或字符串标记(如'[unserializable]') - 确保
config/cache.php中该 store 的type指向你自定义的类名
从业务层杜绝高危写法
框架补丁治标,代码规范治本。以下写法必须清理:
- 禁止
Cache::set(input('key'), input('data'))—— 用户输入未经清洗不得进缓存 - 禁止缓存模型实例(
$user->toArray()才是安全格式) - 禁止缓存容器对象(
app()、Db::name()等返回的构造器) - 所有缓存值在写入前加校验:
is_string($v) || is_numeric($v) || is_array($v),其余一律拦截或转换











