Symfony Serializer反序列化JSON至PHP类返回NULL问题求助
解决Symfony Serializer反序列化后属性为NULL的问题
问题根源
- 私有属性无访问器:Symfony Serializer的
ObjectNormalizer默认无法直接操作私有属性,必须通过getter/setter、反射配置或元数据组件识别属性。 - 嵌套对象类型未被识别:Low/Medium/High类的私有属性和嵌套结构缺少元数据支持,Serializer无法自动实例化这些对象并赋值。
- 构造函数映射缺失:FeeClass的构造参数虽对应JSON键,但若无属性元数据,Serializer无法将JSON值绑定到构造参数。
解决方案
方案一:添加访问器并启用PropertyInfo组件(推荐生产环境)
- 为Low/Medium/High类添加getter/setter,确保属性可被Serializer访问:
class Low { private $networkFee; public function getNetworkFee(): ?string { return $this->networkFee; } public function setNetworkFee(string $networkFee): void { $this->networkFee = $networkFee; } } // Medium和High类复制上述代码,替换类名即可
- 安装Symfony PropertyInfo组件,用于识别属性类型和元数据:
composer require symfony/property-info
- 配置Serializer时注入PropertyInfo提取器:
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; // 初始化属性信息提取器 $phpDocExtractor = new PhpDocExtractor(); $reflectionExtractor = new ReflectionExtractor(); $propertyInfoExtractor = new PropertyInfoExtractor( [$reflectionExtractor], [$phpDocExtractor, $reflectionExtractor], [$phpDocExtractor], [$reflectionExtractor] ); // 配置Serializer $normalizers = [new ObjectNormalizer(null, null, null, $propertyInfoExtractor)]; $encoders = [new JsonEncoder()]; $serializer = new Serializer($normalizers, $encoders); // 执行反序列化 $parsed = $serializer->deserialize((string)$response->getBody(), FeeClass::class, 'json');
方案二:临时改为公开属性(仅用于测试)
若需快速验证,可将类属性改为公开(不推荐生产环境,违反封装原则):
class Low { public $networkFee; } class Medium { public $networkFee; } class High { public $networkFee; } class FeeClass { public $low; public $medium; public $high; }
方案三:使用注解配置属性映射
- 安装注解组件:
composer require symfony/annotation
- 为类添加序列化注解:
use Symfony\Component\Serializer\Annotation\SerializedName; class Low { /** * @SerializedName("networkFee") */ private $networkFee; // 对应getter/setter } class FeeClass { /** * @SerializedName("low") */ private $low; /** * @SerializedName("medium") */ private $medium; /** * @SerializedName("high") */ private $high; public function __construct(Low $low, Medium $medium, High $high) { $this->low = $low; $this->medium = $medium; $this->high = $high; } }
- 配置Serializer启用注解加载:
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Doctrine\Common\Annotations\AnnotationReader; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Encoder\JsonEncoder; $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $normalizers = [new ObjectNormalizer($classMetadataFactory)]; $encoders = [new JsonEncoder()]; $serializer = new Serializer($normalizers, $encoders);
内容的提问来源于stack exchange,提问作者Russo
相关产品推荐
相关产品推荐

