PHP 面试题:PHP 中 json_encode 与 serialize 的区别及选型

在 PHP 面试中,json_encodeserialize 的区别是一个高频考点。很多候选人对这两个函数的认知停留在“一个转 JSON,一个转 PHP 专属格式”的层面,但当面试官继续追问“什么时候用哪个”“为什么缓存里推荐 JSON”“为什么队列里有时必须用 serialize”时,往往就答不上来了。

这篇文章从面试答题的角度,把两者的差异、底层机制、性能表现和选型逻辑一次讲清楚。

一、先看基本定义

serialize() 将 PHP 变量转换为可存储的字节流字符串,格式是 PHP 内部定义的。它保留了变量的完整类型信息,包括对象所属的类名、属性可见性、资源类型标记等。配合 unserialize() 可以还原为原始变量。

json_encode() 将 PHP 变量转换为 JSON 格式字符串,遵循 JSON 标准(RFC 8259)。它只支持 JSON 定义的数据类型:对象、数组、字符串、数字、布尔值和 null。配合 json_decode() 可以还原,但还原后的对象是 stdClass,数组仍是数组。

$data = ['name' => '张三', 'age' => 28, 'tags' => ['PHP', 'MySQL']];

echo serialize($data);
// a:3:{s:4:"name";s:6:"张三";s:3:"age";i:28;s:4:"tags";a:2:{i:0;s:3:"PHP";i:1;s:5:"MySQL";}}

echo json_encode($data);
// {"name":"张三","age":28,"tags":["PHP","MySQL"]}

从输出就能看出核心差异:serialize 保留了 PHP 的类型系统信息(s: 表示字符串、i: 表示整数、a: 表示数组),而 JSON 是跨语言的标准格式。

二、关键差异逐条拆解

1. 数据类型支持范围

serialize 几乎支持 PHP 所有数据类型:

  • 标量类型:int、float、string、bool、null
  • 复合类型:array、object
  • 特殊类型:resource(会被序列化为 i:0,无法真正还原)

json_encode 只支持 JSON 规范内的类型。遇到 resource 会返回 false;遇到对象时只序列化 public 属性;遇到 NANINF 会失败(除非加 JSON_PARTIAL_OUTPUT_ON_ERROR)。

2. 对象处理方式

这是面试中最容易拉开差距的地方。

class User {
    public $name = '张三';
    protected $email = 'zhangsan@example.com';
    private $token = 'abc123';
}

$user = new User();

echo serialize($user);
// O:4:"User":3:{s:4:"name";s:6:"张三";s:8:"\0*\0email";s:20:"zhangsan@example.com";s:11:"\0User\0token";s:6:"abc123";}

echo json_encode($user);
// {"name":"张三"}

serialize 会保留所有属性(包括 protected 和 private),并在属性名中用 \0 标记可见性。json_encode 默认只输出 public 属性。

反序列化时差异更大:unserialize 能还原为原始类实例,json_decode 只能得到 stdClass 对象,需要额外做类型转换。

3. 跨语言与可读性

JSON 是语言无关的标准格式,Python、Java、Go、JavaScript 都能直接解析。serialize 的输出只有 PHP 自己能读懂。

可读性方面,JSON 对人类友好,调试时一眼能看懂;serialize 的字符串对非 PHP 开发者来说几乎不可读。

4. 性能对比

在纯 PHP 场景下,serialize/unserialize 通常比 json_encode/json_decode 更快,因为 JSON 需要处理 UTF-8 编码校验和格式转换。但这个差距在现代 PHP 版本(7.4+、8.x)中已经缩小很多。

实际测试中,简单数组的序列化速度差异在 10%~30% 左右,具体取决于数据结构和 PHP 版本。如果是大对象或嵌套结构,serialize 的优势会更明显。

5. 安全性

两者都有安全隐患,但方向不同:

  • unserialize 存在对象注入风险。如果反序列化的数据来自不可信来源,攻击者可以构造恶意 payload 触发 __wakeup__destruct 等魔术方法,造成远程代码执行。PHP 7 引入了 unserialize($data, ['allowed_classes' => false]) 来缓解。
  • json_decode 本身不涉及对象实例化,安全性更高。但如果解码后直接用于 SQL 拼接或输出到 HTML,仍然需要防注入和 XSS。

6. 数据体积

JSON 通常比 serialize 更紧凑,尤其是纯数组和字符串场景。但 serialize 在存储二进制数据或浮点数时可能更高效。总体而言,JSON 在网络传输中更有优势。

三、选型决策树

面试时可以用下面的逻辑来回答“怎么选”:

优先选 JSON 的场景:

  • 数据需要跨语言、跨系统传输(API 接口、微服务通信)
  • 数据需要存入 MySQL、Redis 等外部存储,且可能被其他语言读取
  • 需要人类可读的调试输出
  • 数据来源不可信,安全要求高
  • 前端 JavaScript 需要直接消费

优先选 serialize 的场景:

  • 纯 PHP 环境内的数据持久化(如 PHP session 的默认序列化处理器)
  • 需要完整保留对象类型和属性可见性
  • 需要序列化实现了 Serializable 接口或含有 __sleep/__wakeup 的对象
  • 对性能极度敏感且数据只在 PHP 内部流转
  • 需要存储 resource 之外的复杂 PHP 数据结构

一个实用的判断口诀: 数据出 PHP 的边界用 JSON,数据只在 PHP 内部流转用 serialize。

四、面试加分回答

如果面试官追问更深,可以补充这几点:

  1. Session 序列化:PHP 默认使用 php 序列化处理器(即 serialize 格式),但可以通过 session.serialize_handler 改为 php_serializeigbinary。igbinary 是更高效的二进制序列化扩展。

  2. Redis 缓存选型:很多团队在 Redis 中存 JSON 而非 serialize,原因是可读性好、跨语言兼容。但如果缓存的是 PHP 对象且需要完整还原,serialize 更合适。

  3. 消息队列:RabbitMQ、Kafka 等跨语言消息队列几乎都用 JSON 或 Protobuf,不会用 serialize。但如果是纯 PHP 的队列系统(如一些基于 Redis 的轻量队列),serialize 可以减少类型转换的麻烦。

  4. JSON 的精度陷阱json_encode 处理大整数或高精度浮点数时可能丢失精度,需要 JSON_BIGINT_AS_STRINGJSON_PRESERVE_ZERO_FRACTION 等选项。serialize 不存在这个问题。

  5. PHP 8.1+ 的新变化serialize 对枚举(Enum)的支持、json_validate() 函数的引入,都是可以提及的加分点。

五、总结

json_encodeserialize 的核心区别不在于“格式不同”,而在于设计目标不同:JSON 是为跨语言数据交换设计的标准格式,serialize 是为 PHP 内部数据持久化设计的类型保真格式。

选型的本质是判断数据的边界:跨出 PHP 就用 JSON,留在 PHP 内就用 serialize。理解这一点,面试时无论怎么追问都不会跑偏。

未经允许不得转载:任鹏个人博客 » PHP 面试题:PHP 中 json_encode 与 serialize 的区别及选型

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏