Contributed by
Samuel Roze
in #24375.

当操作高度相似的对象,或共享很多属性时,使用接口和抽象类就很常见了。对于继承了其他抽象类的类,有一个问题是 Serializer组件 无从得知如何正确地 serialize/deserialize 它们。

在 Symfony 4.1 中,我们改进了 Serializer 组件,通过使用一个 "discriminator class mapping(鉴别器类映射) " 来对此功能进行支持。思考一个程序,它定义了一个抽象类 CodeRepository,该类被 GitHubCodeRepositoryBitBucketCodeRepository 所继承。本例展示了在框架外单纯使用Serializer组件时,如何序列化和反序列化这些对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// ...
 
$discriminator = new ClassDiscriminatorResolver();
// $type is the property used to differentiate between classes
// $type 属性用于区分这些类
$discriminator->addClassMapping(
    CodeRepository::class,
    new ClassDiscriminatorMapping('type', [
        'github' => GitHubCodeRepository::class,
        'bitbucket' => BitBucketCodeRepository::class,
    ])
);
 
// pass the discriminator as the last argument of the normalizer
// 把 discriminator(鉴别器) 作为 normalizer 的最后一个参数传入
$serializer = new Serializer(
    array(new ObjectNormalizer(null, null, null, null, $discriminator)),
    array('json' => new JsonEncoder())
);
 
// when serializing, the discriminator knows that the value of the "type"
// property for GitHubCodeRepository classes must be set to {"type": "github"}
// 序列化时,discriminator 知道 "type" 的值
// GitHubCodeRepository 类中的属性必须被设置为  {"type": "github"}
$serialized = $serializer->serialize(new GitHubCodeRepository());
 
// when deserializing into the abstract CodeRepository class, the discriminator
// uses the "type" value to know that $repository must be an instance of GitHubCodeRepository
// 对 CodeRepository 抽象类反序列化时,discriminator
// 使用 "type" 值来获知 repository 必须是 GitHubCodeRepository 的一个实例
$repository = $serializer->unserialize($serialized, CodeRepository::class, 'json');

在 Symfony 程序中使用此功能时,你可以直接把上述所有在 YAML 或 XML 文件中进行配置 ,甚至使用PHP annotations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace App\Repository;
 
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
 
/**
 * @DiscriminatorMap(typeProperty="type", mapping={
 *    "github"="App\Repository\GitHubCodeRepository",
 *    "bitbucket"="App\Repository\BitBucketCodeRepository"
 * })
 */
interface CodeRepository
{
    // ...
}

关于此项新功能的更多内容请参考 Serializer组件文档中的 Serializing Interfaces and Abstract Classes 小节。