PHP序列化的四种实现方法与横向对比

发布时间:2026/10/9 9:45:47

PHP序列化的四种实现方法与横向对比 前言先说清楚一件事「PHP 序列化的四种实现方法」并不是官方给出的分类。PHP 手册里没有这样一节官方只有在「对象序列化」章节里介绍了serialize()/unserialize()这一套机制。这个「四种」的说法来自社区的口头归纳通常指的是下面四条互不相同的路线内置的serialize()/unserialize()内置的json_encode()/json_decode()var_export()配合include注意它产出的是PHP 代码不是数据需要额外安装的第三方扩展比如 igbinary、msgpack。把它当成一份「候选清单」来看是对的当成「官方标准」来看就会出错。这四者的差异不只是速度更关键的是三件事类型是否保真、能不能跨语言读、以及还原时会不会执行代码。第 3 条的答案最危险——include一段var_export()产物本质上是在执行代码只要那段文本能被外部影响就是代码执行漏洞。本文按「机制 → 横向对比 → 可跑的实测脚本 → 选择清单」展开所有函数签名都以官方手册为准。一、四条路线各自的机制1. serialize() / unserialize()PHP 亲儿子。它保留完整的类型信息int和123不会混支持数组、对象、引用和循环引用输出是可能含空字节的二进制串。代价是只有 PHP 能读且还原对象时会调用类里的魔术方法因此对不可信输入极其危险。官方手册对它的定位是「生成可存储的表示」并且明确建议如果需要把数据交给用户请改用 JSON。?php // 适用于 PHP 7.0$value [id 1001, vip true, name ann];$raw serialize($value);echo $raw, PHP_EOL;// a:3:{s:2:id;i:1001;s:3:vip;b:1;s:4:name;s:3:ann;}2. json_encode() / json_decode()输出纯文本、UTF-8、跨语言通用是接口之间的默认选择。它的边界也很清楚只有标量、数组、对象能编码官方手册写明「值可以是除 resource 之外的任意类型」对象默认只输出 public 属性想让类自己决定怎么变成 JSON需要实现JsonSerializable接口数字类型有损超过PHP_INT_MAX的整数解码回来会变成 float需要JSON_BIGINT_AS_STRING浮点输出受serialize_precision影响手册明确写了这一点它不会按类名实例化你的类因此对不可信输入要安全得多。?php // 适用于 PHP 7.3JSON_THROW_ON_ERROR 需要 7.3$json json_encode([id 1001, vip true], JSON_THROW_ON_ERROR);echo $json, PHP_EOL; // {id:1001,vip:true}// 第二个参数决定 JSON 对象解码成关联数组true还是 stdClassfalse/nullvar_dump(json_decode($json, true));3. var_export() 配合 include签名是var_export(mixed $value, bool $return false): ?string第二个参数传true时返回字符串而不直接输出。它产出的是合法的 PHP 代码常见于生成配置文件、写缓存文件。官方手册在 Notes 里给了三条重要限制资源类型无法被导出它不处理循环引用因为几乎不可能为循环结构生成可解析的 PHP 代码要处理这种数据请用serialize()而且所有被导出的对象都必须实现静态方法__set_state()唯一的例外是stdClass它用「数组转对象」的形式导出。另外PHP 8.2.0 之前的版本在导出命名空间类时不会带上开头的反斜杠跨命名空间求值时容易出错。?php // 适用于 PHP 8.0$config [debug false, level 3, hosts [a.test, b.test]];$code var_export($config, true);$file sys_get_temp_dir() . DIRECTORY_SEPARATOR . demo_config.php;file_put_contents($file, ?php return . $code . ;);$loaded include $file;var_dump($loaded $config);unlink($file);4. 第三方扩展igbinary、msgpackigbinary 是一个把 PHP 结构编成紧凑二进制流的扩展手册里有igbinary_serialize(mixed $value): string|false与igbinary_unserialize(string $str): mixed两个函数它同时可以作为 session 与 Memcached/Redis 的序列化器使用。msgpack 走的是跨语言的二进制路线函数名以该扩展自己的文档为准它不是 PHP 内置的一部分。这两者的共同点是必须先安装扩展在php.ini里开启或用包管理器装部署环境、版本升级都要考虑用之前先function_exists()判断缺扩展时要有降级路径。?php // 适用于 PHP 7.0需要安装 igbinary 扩展$value [id 1001, name ann];if (!function_exists(igbinary_serialize)) {exit(当前环境没有安装 igbinary 扩展 . PHP_EOL);}$packed igbinary_serialize($value);var_dump(is_string($packed), igbinary_unserialize($packed) $value);二、横向对比维度serialize()json_encode()var_export() includeigbinary / msgpack输出形态二进制串UTF-8 文本PHP 代码二进制流类型保真完整int/float/string 区分数字只有一种大整数会退化完整还原后就是原值与 serialize 接近跨语言否是否msgpack 是igbinary 否对象支持保存属性触发魔术方法默认只输出 public 属性需要__set_state()保存属性循环引用支持不支持不支持igbinary 支持还原时执行代码会实例化类、跑魔术方法不会会执行文件里的代码同 serialize外部依赖无无JSON 扩展默认开启无需要额外安装扩展适合场景PHP 内部缓存、队列、session接口、日志、跨语言交换可信来源的配置/代码生成追求体积与速度的 PHP 内部缓存三、可跑的实测脚本下面这段代码把同一个数据结构用四条路线各走一遍打印体积并逐个验证「能还原成原样」。体积那一列是你自己机器上跑出来的结果不同 PHP 版本和扩展版本会有差异请以实际输出为准。?php // 适用于 PHP 8.0JSON_THROW_ON_ERROR 需要 7.3declare(strict_types1);$order [id 1001,user [name ann, vip true],total_cents 1999,tags [php, json],];$payloads [];// 1) serialize()$payloads[serialize] serialize($order);// 2) json_encode()$payloads[json] json_encode($order, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);// 3) var_export()注意它产出的是代码$payloads[var_export] var_export($order, true);// 4) 第三方扩展装没装决定了这一行是不是降级提示$payloads[igbinary] function_exists(igbinary_serialize)? igbinary_serialize($order): (未安装 igbinary 扩展);foreach ($payloads as $name $payload) {printf(%-12s %5d 字节\n, $name, strlen((string)$payload));}// 逐个还原并比对var_dump(serialize , unserialize($payloads[serialize]) $order);var_dump(json , json_decode($payloads[json], true, 512, JSON_THROW_ON_ERROR) $order);$file sys_get_temp_dir() . DIRECTORY_SEPARATOR . exported_order.php;file_put_contents($file, ?php return . $payloads[var_export] . ;);var_dump(var_export , (include $file) $order);unlink($file);体积差异的原因值得记住但不要记具体倍数serialize()要为每个元素写类型标记和长度var_export()要写成带引号和缩进的 PHP 代码通常最臃肿JSON 去掉了类型标记但要把非 ASCII 字符转义加JSON_UNESCAPED_UNICODE可以避免而 igbinary 是为紧凑设计的二进制格式。真正的性能差异取决于数据形态、是否命中 Opcache、以及缓存后端是否走网络不实测就不要下结论。常见坑点❌ 认为var_export()的输出是「数据」把它和用户输入拼在一起再include或eval。✅ 它产出的是 PHP 代码include等于执行代码只能用于完全可信的来源。跨系统的数据交换用 JSON。❌ 用json_encode()编码一个对象后发现部分属性不见了。✅ 默认只输出 public 属性需要输出全部则实现JsonSerializable::jsonSerialize()不要靠(array)强制转换转换后私有属性名会带上\0前缀。❌ 用var_export()保存带循环引用的结构或者保存对象后直接include回来。✅ 手册明确说var_export()不处理循环引用导出对象还要求类实现静态__set_state()只有stdClass例外它导出成数组转对象的形式。❌ 把serialize()的产物当作「可安全传给前端」的字符串。✅ 它可能在还原时实例化类并触发魔术方法手册的警告是「无论选项怎么设都不要把不可信输入交给unserialize()」。对外一律用 JSON。❌ 在没确认扩展是否安装的情况下直接调用igbinary_serialize()。✅ 先function_exists(igbinary_serialize)并在部署清单里写明依赖扩展缺失时应降级到serialize()而不是让页面 500。❌ 用md5()/sha1()给序列化串「盖个章」当作防篡改。✅ 需要防篡改用带密钥的hash_hmac()比较用hash_equals()md5()/sha1()都不适合做完整性校验更绝对不能用来存密码存密码用password_hash()/password_verify()。❌ 为了「体积小」手动截断 JSON 或序列化串。✅ 两者都是有结构的编码截断必然损坏限制体积要靠精简字段、加JSON_UNESCAPED_UNICODE之类的正确手段或者换更紧凑的格式。❌ 在同一个项目里混用多种格式缓存键却不带格式标识。✅ 缓存键里带上格式名与版本号例如order:v2:json否则改格式那天会读出一堆「反序列化失败」。总结需求首选理由对外接口、跨语言交换json_encode()/json_decode()文本、通用、不会按类名实例化对象PHP 内部缓存、队列、sessionserialize()或 igbinary类型保真、支持引用与循环结构生成配置或代码文件var_export()产物是可直接include的 PHP 代码仅限可信来源追求体积与速度igbinary / msgpack二进制紧凑格式但需自行安装与维护扩展四者之间的关系不是「谁取代谁」而是「谁适合哪条边界」只要数据要跨越你的信任边界面向用户、面向其他语言、面向其他团队答案就是 JSON只要数据只在你的 PHP 代码之间往返serialize()或 igbinary 才是更保真的选择而var_export()输出的是代码而不是数据这一点决定了它只能待在极窄的可信场景里。
延伸阅读

更多相关文章

2026/10/9 9:45:47

学生宿舍管理系统数据库课设:从需求分析到SQL实施全解析

简介:学生宿舍管理信息系统数据库课程设计报告是一份面向数据库课程设计场景的完整文档,适合计算机、信息管理类学生参考选题、开题、设计及答辩材料撰写。报告共42页约11014字,围绕管理员、学生、领导人三种用户角色,系统覆盖需求…

2026/10/9 9:45:47

WAV与MP3底层原理:保真编辑vs传播兼容的音频格式选择指南

1. 为什么今天还要认真搞懂WAV和MP3?——一个音频从业者踩了七年坑才理清的底层逻辑你有没有遇到过这种情况:导出一段录音,发给同事听,对方说“声音发闷、细节全没了”;或者在剪辑软件里拖进一个MP3,波形图…

2026/10/9 13:57:06

双端影视APP源码修复实战:从编译失败到可调试基线

简介:这是一套开箱即用的双端影视APP无加密修复版源码,面向有苹果CMS建站基础的开发者或个人站长,解决影视类小程序/APP快速落地、双端(AndroidiOS)同步上线及商业化运营难题。资源包含673个文件,以312张UI…

2026/10/9 13:57:06

VSCode tasks.json 变量替换全解析:从 ${file} 到 ${input} 的避坑指南

简介:这份PDF资料聚焦VSCode tasks.json中的各类替换变量,面向使用VSCode进行任务配置的开发者,尤其是需要编写构建、编译、自动化脚本的中级用户。内容系统梳理了${workspaceFolder}、${file}、${fileBasename}、${fileDirname}、${relative…

2026/10/9 13:57:06

题解:洛谷 P2909 [USACO08OPEN] Cow Cars S

本文分享的必刷题目是从蓝桥云课、洛谷、AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。 欢迎大…

2026/10/9 13:57:06

自动化测试入门到进阶:从接口到UI打造稳定高效测试体系

只要你打开任何一个测试岗位的招聘要求,几乎都能看到“熟悉自动化测试”这一条。很多刚入行或者转行的朋友,第一反应是自动化测试是不是对代码要求特别高,是不是只有大厂才玩得转。我做了几年测试开发和自动化测试落地,想说句实话…

2026/10/9 13:52:05

impeccable:用工程化手段将代码质量变成默认状态

1. 一个词引发的项目灵感:为什么是“impeccable”第一次看到“impeccable”这个词,是在一次跨团队协作的复盘会上。当时有人用它来形容一个交付物——“impeccable”,意思是无可挑剔、零瑕疵。我当时就想,如果把这个词变成一个项目…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 0:04:27

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略当数万字的学位论文初稿经历开题、实验、问卷与多轮文献梳理最终成形时,绝大多数研究生都会面临一道全新的形式审查关卡:AIGC 疑似度排查。在高校毕业审核流程中,盲审前的文本检测通…

2026/10/9 0:04:27

食堂节能改造源头工厂,商用厨房设备焕新方案广受好评

商用厨房作为餐饮经营、单位供餐的核心后勤阵地,其设备配置、动线规划与运维体系直接决定后厨作业效率、运营成本与合规性。从基础的灶具、制冷存储设备,到油烟净化、水处理等配套系统,每一个环节的合理性都与食品安全、能耗管控、消防安全挂…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑