PHP中serialize和unserialize是原生序列化函数,可将对象/数组转为含类型信息的字符串并还原,但存在反序列化漏洞风险;而JSON方式跨语言兼容但不支持资源和私有属性。

直接用 SerializerInterface::deserialize() 解析 JSON 字符串
只要 JSON 格式合法,$serializer->deserialize($jsonString, Customer::class, 'json') 就能生成对应对象。但前提是类里字段可写(public 属性或有 setter),且 Serializer 已配置好 ObjectNormalizer 和 JsonEncoder。如果目标是数组,第二个参数必须写 'array',不能传空或 null —— 否则会抛出 NotNormalizableValueException。
- 确保实体类字段名和 JSON key 一致,或用
@SerializedName("user_name")显式映射 - 若 JSON 中字段缺失,属性值不会自动设为 null:构造函数赋初值、setter 兜底、或启用
setIgnoreMissingProperties(false)配合@Default注解 - 遇到
"Cannot create an instance of class X",大概率是类没 public 构造函数,或缺少无参构造器
反序列化时关联 ID 怎么不新建对象
JSON 里带 "author_id": 123,而不是完整 author 对象,直接反序列化默认会尝试 new Author(),失败或脏数据。必须干预对象构建流程。
- 禁用自动实例化:在
ObjectNormalizer配置中设setAllowEmptyObjects(false) - 预加载后填充:先查出
$author = $em->find(Author::class, $data['author_id']),再调用deserialize()时传['object_to_populate' => $customer] - 更可控的做法是用 DTO + 自定义 denormalizer,在 denormalize() 里手动查库并 set 关联
json_decode() 和 Serializer::deserialize() 到底该选哪个
纯结构转换(比如 API 响应解析成数组)用 json_decode($content, true) 更快、更轻量;需要类型校验、字段映射、嵌套对象还原、或统一走验证逻辑时,必须用 Serializer。
-
json_decode()不做类型检查,int字段传字符串也不会报错,后续运行时才崩 -
Serializer能结合 Validator 组件,在反序列化阶段就触发约束校验(如@Assert\NotBlank) - 对加密 JSON,必须先解密再交给
Serializer;若直接传密文,JsonEncoder会报SyntaxError
缓存/队列/表单场景下别误用 Form 对象本身
表单对象(FormInterface)不是数据载体,它是控制器逻辑的一部分。想转 JSON 或数组,永远只取 $form->getData() 返回的实体或数组,而不是 $form 实例。
- Redis 缓存项如果是
CacheInterface存的数组,读出来就是数组;如果是 raw string,先json_decode($raw, true),别盲目unserialize() - 队列消息体是 JSON 字符串?直接
json_decode($msg->getBody(), true);是对象?优先在类里实现toArray(),别依赖 Serializer 多绕一圈 - 表单提交后,
isValid()通过才调getData(),否则数据不可信
实际项目里最常漏掉的是错误兜底:解密失败、JSON 格式损坏、反序列化类型不匹配——这三类异常必须分开 catch,记录上下文(原始字符串、key、时间戳),否则线上排查等于盲人摸象。











