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

如何用Symfony Serializer将JSON反序列化为含实体数组的DTO

解决Symfony Serializer反序列化对象数组的问题

问题根源在于Symfony Serializer无法自动推断数组内的对象类型,必须显式指定数组元素的DTO类型,同时确保Serializer能读取到这些类型元数据。以下是具体实现步骤:

1. 为DTO属性添加类型元数据

根据你的PHP版本选择对应的方式:

方式一:PHP注解(兼容PHP 7+)

给ArrDTO的arr属性添加@Type注解,明确数组元素为SomeDTO:

namespace App\DTO;

use Symfony\Component\Serializer\Annotation\Type;

class SomeDTO
{
    private int $id;
    private string $name;

    // 生成对应的getter和setter方法
    public function getId(): int { return $this->id; }
    public function setId(int $id): void { $this->id = $id; }
    public function getName(): string { return $this->name; }
    public function setName(string $name): void { $this->name = $name; }
}

class ArrDTO
{
    /**
     * @Type("array<App\DTO\SomeDTO>")
     */
    private array $arr;

    // 生成对应的getter和setter方法
    public function getArr(): array { return $this->arr; }
    public function setArr(array $arr): void { $this->arr = $arr; }
}

方式二:PHP 8+属性

用PHP原生属性替代注解,写法更简洁:

namespace App\DTO;

use Symfony\Component\Serializer\Annotation\Type;

class SomeDTO
{
    private int $id;
    private string $name;

    // getter和setter同上
}

class ArrDTO
{
    #[Type('array<App\DTO\SomeDTO>')]
    private array $arr;

    // getter和setter同上
}

方式三:PHP 8.1+泛型类型(推荐)

如果使用PHP 8.1及以上,可直接用泛型数组声明,配合PhpDoc提示:

namespace App\DTO;

class SomeDTO
{
    private int $id;
    private string $name;

    // getter和setter同上
}

class ArrDTO
{
    /** @var list<SomeDTO> */
    private array $arr;

    // 或者直接用PHP 8.1泛型语法:
    // private array<SomeDTO> $arr;

    // getter和setter同上
}

2. 确保Serializer能读取类型元数据

独立使用Serializer(非Symfony框架)

需要手动初始化Serializer,加载注解/属性元数据:

use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Doctrine\Common\Annotations\AnnotationReader;

// 加载注解元数据(如果用注解方式)
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));

// 初始化Serializer
$normalizers = [new ObjectNormalizer($classMetadataFactory)];
$encoders = [new JsonEncoder()];
$serializer = new Serializer($normalizers, $encoders);

// 执行反序列化
$jsonData = '{"arr": [{"id":1,"name":"test1"},{"id":2,"name":"test2"}]}';
$arrDto = $serializer->deserialize($jsonData, ArrDTO::class, 'json');

// 此时$arrDto->getArr()返回的是SomeDTO对象数组

Symfony框架内使用

框架默认已配置好Serializer服务,只需确保安装了必要依赖:

  • 若用注解:安装doctrine/annotations
  • 若用PHP属性:无需额外依赖,直接注入SerializerInterface即可

示例控制器代码:

namespace App\Controller;

use App\DTO\ArrDTO;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Serializer\SerializerInterface;

class TestController extends AbstractController
{
    public function deserialize(Request $request, SerializerInterface $serializer)
    {
        $jsonData = $request->getContent();
        $arrDto = $serializer->deserialize($jsonData, ArrDTO::class, 'json');
        
        // 后续逻辑
    }
}

注意事项

  • 确保DTO类的属性有对应的getter和setter方法,否则Serializer无法正常赋值(或配置ObjectNormalizer允许直接访问私有属性)
  • 若使用泛型方式,需确保Serializer启用了PhpDoc元数据加载(Symfony框架默认已启用)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:37:31