PHP 7.1 中 resource 类型无法被 serialize() 序列化,因其是依赖运行时环境的外部系统句柄,不可持久化;序列化时会跳过或失败,反序列化后变为 null,需提前剥离、用标识替代或重写 __sleep() 规避。

PHP 7.1 中,资源(resource)类型无法被 serialize() 序列化,这是语言层面的硬性限制,不是版本 Bug 或配置问题。一旦数组里包含资源(如文件句柄、数据库连接、cURL 句柄等),调用 serialize() 时会直接跳过该元素,或导致整个序列化失败(取决于上下文),反序列化后对应位置变成 null 或丢失,从而引发后续逻辑错误。
为什么资源不能序列化
资源是 PHP 内部指向外部系统(如操作系统文件描述符、MySQL 连接套接字)的抽象句柄,不具备可持久化的状态。它依赖运行时环境,无法被转换为字符串形式保存或跨请求传递。PHP 明确将 resource 排除在 serialize() 支持类型之外——这点从 PHP 4 到 8 均未改变。
常见出问题的场景
- 缓存一个含
fopen()返回值的数组(例如日志上下文) - ThinkPHP 或 Laravel 的某些调试/记录组件临时存了
mysqli或PDO实例(实际是资源) - 使用
curl_init()后把句柄塞进配置数组再尝试缓存 - 自定义类中属性为 resource,且未实现
__sleep()过滤该字段
实用解决策略
核心原则:**不序列化资源,只序列化能还原资源的信息**。
-
提前剥离资源:序列化前遍历数组,用
is_resource()检测并移除或替换资源项。例如:$safeArray = array_map(function($v) { return is_resource($v) ? null : $v; }, $originalArray); - 用标识代替资源:若资源代表某个可重建对象(如数据库连接),改存连接参数(host/user/dbname)或唯一 ID,反序列化后再按需重建;避免把连接本身当“数据”缓存。
-
重写 __sleep() 方法:对含资源属性的类,在
__sleep()中显式返回不含资源属性的键名列表,确保序列化安全。例如:public function __sleep() { return ['id', 'name']; // 不返回 $this->fileHandle - 换用 JSON 等无状态格式:JSON 天然拒绝 resource,会直接报错(比静默丢失更早暴露问题),迫使你在序列化前做清理。
特别注意 ThinkPHP 等框架的缓存驱动
部分框架缓存类(如 think\cache\driver\File)默认调用 serialize()。若你传入含资源的数据,即使没报错,也会造成缓存内容损坏。建议:在写入缓存前统一做资源过滤,或继承缓存驱动、重写 serialize() 方法,加入资源检测逻辑(参考知识库中 SerializableFile 示例)。
立即学习“PHP免费学习笔记(深入)”;



















