You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Symfony Serializer基于属性序列化/反序列化含对象属性的对象?

基于Symfony Serializer实现类属性级别的序列化与反序列化

要实现仅基于类属性而非get/set/is方法的序列化、反序列化(包含嵌套对象的场景),可以通过正确配置PropertyNormalizer并配合类型解析、对象构造支持来解决。以下是具体方案:

核心配置思路

PropertyNormalizer本身支持直接操作类属性,但默认不会自动处理嵌套对象的类型转换。需要开启类型属性支持、配置对象构造器,并配合EnumNormalizer处理枚举类型,就能解决反序列化时的类型错误问题。

步骤1:确保依赖安装

确保项目已安装以下Symfony组件:

composer require symfony/serializer symfony/property-access symfony/validator
  • symfony/validator用于读取PHPDoc注解中的类型信息(如果不用PHP原生类型属性的话)。

步骤2:配置Serializer服务

手动创建Serializer实例时,需要将PropertyNormalizer、EnumNormalizer(处理枚举)和JsonEncoder组合,并给PropertyNormalizer设置关键选项:

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Normalizer\EnumNormalizer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ReflectionObjectConstructor;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;

// 创建类型信息提取器:结合PHPDoc和反射获取属性类型
$phpDocExtractor = new PhpDocExtractor();
$reflectionExtractor = new ReflectionExtractor();
$propertyInfoExtractor = new PropertyInfoExtractor(
    [],
    [$phpDocExtractor, $reflectionExtractor]
);

// 配置PropertyNormalizer:启用类型属性支持,指定对象构造器
$propertyNormalizer = new PropertyNormalizer(
    null,
    null,
    null,
    $propertyInfoExtractor,
    new ReflectionObjectConstructor()
);
$propertyNormalizer->setDefaultContext([
    PropertyNormalizer::ENABLE_TYPED_PROPERTIES => true, // 启用类型属性解析
    PropertyNormalizer::ALLOW_EXTRA_ATTRIBUTES => false, // 禁止额外属性
]);

// 组合Serializer
$serializer = new Serializer(
    [$propertyNormalizer, new EnumNormalizer()],
    [new JsonEncoder()]
);

步骤3:序列化与反序列化示例

序列化

直接调用serialize方法,只会序列化类属性,不会包含getFullName()、getType()等业务方法的返回值:

// 创建测试对象
$workAddress = new Address();
$workAddress->setCity('LA');
$workAddress->setStreet('Central');
$workAddress->setAddressType(AddressTypeEnum::Work());

$homeAddress = new Address();
$homeAddress->setCity('Washington');
$homeAddress->setStreet('Some street');
$homeAddress->setAddressType(AddressTypeEnum::HOME());

$user = new User();
$user->setName('Tom');
$user->setSurname('Tailor');
$user->setAddresses([$workAddress, $homeAddress]);

// 序列化
$json = $serializer->serialize(['user' => $user], 'json', [
    'json_encode_options' => JSON_PRETTY_PRINT
]);

echo $json;

输出结果将和你期望的一致。

反序列化

调用deserialize方法,指定目标类型,Serializer会自动将嵌套数组转换为对应的对象:

$jsonData = '{
    "user": {
        "name": "Tom",
        "surname": "Tailor",
        "addresses": [
            {
                "addressType": "Work",
                "city": "LA",
                "street": "Central"
            },
            {
                "addressType": "Home",
                "city": "Washington",
                "street": "Some street"
            }
        ]
    }
}';

// 反序列化到数组,再提取User对象
$data = $serializer->deserialize($jsonData, 'array', 'json');
$user = $serializer->denormalize($data['user'], User::class);

// 验证结果
var_dump($user->getName()); // 输出 "Tom"
var_dump($user->getAddresses()[0] instanceof Address); // 输出 bool(true)
var_dump($user->getAddresses()[0]->getAddressType()->getValue()); // 输出 "Work"

关键说明

  1. 类型信息的重要性:确保类属性有明确的PHP类型声明,或者通过PHPDoc注解(比如/** @var Address[] */)标注类型,这样PropertyNormalizer才能正确识别嵌套对象的类型,完成自动转换。
  2. ReflectionObjectConstructor:该构造器通过反射直接实例化对象,不需要依赖setter方法,确保反序列化时能直接给私有属性赋值。
  3. EnumNormalizer:专门处理枚举类型的序列化/反序列化,将枚举值转换为字符串,反序列化时再还原为枚举实例。

内容的提问来源于stack exchange,提问作者Wiktor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 23:24:58