当前位置:首页 > 文章列表 > 文章 > php教程 > PHP 反序列化后为什么得到 __PHP_Incomplete_Class

PHP 反序列化后为什么得到 __PHP_Incomplete_Class

来源:17golang原创 2026-11-08 00:22:15 0浏览 收藏

PHP 反序列化后出现 __PHP_Incomplete_Class,通常不是对象属性突然丢失,而是 PHP 找不到序列化数据所指向的原类,或者 allowed_classes 明确把这个类排除在外。先记住判断顺序:看序列化数据里的类名,再看当前请求是否加载了这个类,最后看反序列化选项是否允许它。

官方手册:https://www.php.net/manual/en/class.php-incomplete-class.php

这个占位对象表示“对象数据读到了,但原来的业务类没有按当前规则恢复”。修复重点是补齐类加载或调整明确的白名单;如果数据来自用户或外部系统,不要为了恢复对象而放宽到任意类,优先改用 JSON 等数据格式。
  • 类未定义、命名空间不一致或自动加载没有生效,会让对象退化为不完整对象。
  • allowed_classes 为 false,或数组里没有目标类,同样会产生不完整对象。
  • unserialize() 返回 false 并伴随 Warning,属于输入格式失败,和不完整对象不是同一条分支。

先看它为什么不是原来的业务类

序列化对象时,字符串中会带有类名。反序列化时,PHP 需要根据这个名字找到当前进程中的类定义;如果类不存在,就只能保留已读到的属性,并用 __PHP_Incomplete_Class 表示“没有完成业务类恢复”。这个类不是应该由业务代码主动创建的模型类,而是 PHP 为异常恢复状态提供的占位。

PHP 反序列化时原类对象与不完整对象的关系说明图
图1:对象类型关系说明图;类未加载或不在白名单时,PHP 会保留对象数据但使用不完整对象占位。

可以先用一个不存在的类名观察这个现象。下面的字符串只用于说明诊断边界,不代表生产代码应该手工拼接序列化数据。

__PHP_Incomplete_Class_Name);
}
?>

如果输出的原始类名是 MissingProfile,说明排查方向应放在类文件、命名空间和自动加载,而不是先去修改属性名。实际项目中也可能是发布顺序造成的:写入数据的服务已经部署了新类,读取数据的服务还没有加载对应版本。

把类未加载和白名单排除分开

第二个常见原因是调用方主动限制了可恢复的类。allowed_classes 可以是布尔值或类名数组;设置为 false 时不接受对象类,设置为数组时只接受列出的类。目标类没有出现在数组里,即使类文件已经被加载,也会得到 __PHP_Incomplete_Class。

 false]);
var_dump(get_class($blocked));

// 只允许名单中的类;名单不包含 UserProfile 时同样会被排除。
$limited = unserialize($payload, ['allowed_classes' => [DateTimeImmutable::class]]);
var_dump(get_class($limited));
?>

这一步最容易误判:如果把所有问题都归因于自动加载,就会漏掉调用方的安全配置;如果为了让旧代码继续运行而直接把白名单改成“全部允许”,又会失去类过滤的意义。诊断时应把“类是否已加载”和“规则是否允许”分别记录。

按三个证据点定位原因

排查不需要猜测,可以固定看三个证据点:

  1. 序列化数据中的类名:从 __PHP_Incomplete_Class_Name 或数据生产端的类定义确认完整类名,特别注意命名空间大小写和反斜杠。
  2. 当前进程的类加载状态:检查 Composer 自动加载入口是否在反序列化之前执行,或者确认手工 require_once 的文件确实定义了同名类。
  3. allowed_classes 规则:沿调用链找到真正执行 unserialize() 的位置,确认是否为 false,或数组中是否漏掉了目标类。
PHP 反序列化三类证据点排查关系说明图
图2:排查关系说明图;先核对数据里的类名,再核对加载状态,最后核对 allowed_classes。

如果三项都正常,却仍然出现不完整对象,再检查读取端和写入端是否使用了不同命名空间、不同版本的类名,或者当前请求是否走了另一条缓存/队列消费路径。不要只在数据库里搜索属性值;这个问题首先是类解析问题。

修复时优先恢复明确的类边界

对于可信的内部存量数据,修复通常有两步:在反序列化之前完成自动加载,并只把业务上确实需要恢复的类放入白名单。下面示例用类型判断阻止不完整对象继续进入业务逻辑。

 [UserProfile::class],
]);

// 类型不符合预期时立即停在边界,避免继续访问业务属性。
if (!$value instanceof UserProfile) {
    throw new UnexpectedValueException('对象类型不是 UserProfile');
}

echo $value->name;
?>

如果数据来自请求参数、Cookie、上传文件或不受信任的外部系统,不应把“恢复成功”当成目标。PHP 手册明确提醒不要对不可信输入使用 unserialize();这类场景应把数据模型改成 JSON,并在读取后做字段和类型校验。allowed_classes 是缩小对象恢复范围的措施,不是把不安全输入变安全的替代品。

最后用类型和原始类名复查

修复后不要只看页面没有报错,而要确认返回值已经是预期类。可以保留一段很小的边界记录:业务对象进入服务层前,使用 instanceof 判断;遇到不完整对象时记录原始类名和数据来源,不要把它重新序列化后继续传递。

name;
} elseif ($value instanceof __PHP_Incomplete_Class) {
    // 原始类名用于定位加载或白名单问题,不用于绕过限制。
    $className = $value->__PHP_Incomplete_Class_Name ?? 'unknown';
    error_log('Incomplete serialized class: ' . $className);
} else {
    // 其他类型可能来自错误输入或版本不兼容,需要单独处理。
    throw new UnexpectedValueException('反序列化结果类型不符合预期');
}
?>

常见问题

出现 __PHP_Incomplete_Class 是不是说明序列化字符串损坏?

不一定。它更常见地表示类未定义或被 allowed_classes 排除;字符串格式损坏通常会走返回 false 和 Warning 的错误分支。

把 allowed_classes 改成 true 就能解决吗?

它可能绕过白名单排除,但不应该作为通用修复。先确认目标类、自动加载和数据来源,再按最小范围列出允许恢复的类。

能不能直接 new __PHP_Incomplete_Class?

不要这样设计业务代码。它是 unserialize() 在特定条件下创建的占位状态,正确做法是修复类加载/白名单边界,或改用适合外部数据的格式。

为什么开发环境正常,线上却出现这个对象?

重点比较两边的 Composer 自动加载入口、命名空间、部署版本和 allowed_classes 配置。写入端和读取端的类名不一致,也会造成同样现象。

小结

__PHP_Incomplete_Class 可以理解为 PHP 在反序列化过程中的“保留数据、暂停恢复”状态。先拿到原始类名,再确认类是否已加载,最后检查 allowed_classes;对可信内部数据修复明确的加载和白名单,对不可信外部数据则优先停止使用 unserialize(),改用 JSON 等数据交换格式。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
2026 云原生生态有哪些值得持续观察的工程方向2026 云原生生态有哪些值得持续观察的工程方向
上一篇
2026 云原生生态有哪些值得持续观察的工程方向
PHP 8.5 clone() 在 readonly 对象中更新属性的处理方法
下一篇
PHP 8.5 clone() 在 readonly 对象中更新属性的处理方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    933次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    938次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1047次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1019次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    846次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码