Serializer组件
编辑本页警告:您正在浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 3.0,现已不再维护。
读本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。
Serializer组件
Serializer组件用于将对象转换为特定的格式(XML、JSON、YAML等),或者将对象转换为特定的格式。
为此,Serializer组件遵循以下简单模式。
正如你在上图中看到的,一个数组被用作中间的一个人。这样,编码器将只处理特定的转向格式成数组反之亦然。同样,Normalizers将处理转向特定对象成数组反之亦然。
序列化是一个复杂的主题,虽然这个组件可能不是在所有情况下都能工作,但在开发序列化和反序列化对象的工具时,它可能是一个有用的工具。
安装
你可以用两种不同的方式安装组件:
- 通过Composer安装(
欧宝娱乐app下载地址symfony /序列化器
在Packagist); - 使用官方Git存储库(https://github.com/欧宝娱乐app下载地址symfony/serializer).
然后,要求供应商/ autoload.php
文件以启用Composer提供的自动加载机制。否则,您的应用程序将无法找到这个Symfony组件的类。欧宝娱乐app下载地址
使用ObjectNormalizer
,PropertyAccess组件也必须安装。
使用
使用Serializer组件非常简单。你只需要设置序列化器指定哪些编码器和规范化器将可用:
1 2 3 4 5 6 7 8 9
使用欧宝娱乐app下载地址\组件\序列化器\序列化器;使用欧宝娱乐app下载地址\组件\序列化器\编码器\XmlEncoder;使用欧宝娱乐app下载地址\组件\序列化器\编码器\JsonEncoder;使用欧宝娱乐app下载地址\组件\序列化器\标准化者\ObjectNormalizer;$编码器=数组(新XmlEncoder (),新JsonEncoder ());$标准化者=数组(新ObjectNormalizer ());$序列化器=新序列化器($标准化者,$编码器);
首选的归一化器是ObjectNormalizer,但其他归一化器是可用的。下面显示的所有示例都使用ObjectNormalizer
.
序列化对象
在这个例子中,假设你的项目中已经存在以下类:
12 34 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 32 33 34 35 36 37 38 39 40 41
名称空间Acme;类人{私人$年龄;私人$的名字;私人$运动员;/ /读取器公共函数getName(){返回$这->名称;}公共函数getAge(){返回$这->年龄;}/ /伊塞公共函数isSportsman(){返回$这->运动员;}/ / setter公共函数setName($的名字){$这->name =$的名字;}公共函数setAge($年龄){$这->年龄=$年龄;}公共函数setSportsman($运动员){$这->运动员=$运动员;}}
现在,如果你想将这个对象序列化为JSON,你只需要使用之前创建的Serializer服务:
1 2 3 4 5 6 7 8 9 10
$人=新Acme \人();$人->setName (“foo”);$人->setAge (99);$人->setSportsman (假);$jsonContent=$序列化器->序列化($人,json的);// $jsonContent包含{"name":"foo","age":99,"sportsman":false}回声$jsonContent;//或在响应中返回它
的第一个参数serialize ()在这种情况下,对象是要序列化的,第二个是用来选择合适的编码器的吗JsonEncoder.
反序列化一个对象
现在你将学习如何做完全相反的事情。这一次,信息的人
类将以XML格式编码:
1 2 3 4 5 6 7 8 9
$数据=<< foo 99 false EOF; $人=$序列化器->反序列化($数据,“Acme \人”,“xml”);
在这种情况下,反序列化()需要三个参数:
- 要解码的信息
- 此信息将被解码到的类的名称
- 用于将该信息转换为数组的编码器
在现有对象中反序列化
序列化器也可以用来更新现有对象:
12 3 4 5 6 7 8 9 10 11 12 13 14
$人=新Acme \人();$人->setName (“酒吧”);$人->setAge (99);$人->setSportsman (真正的);$数据=< < < EOF <人> <名称> foo < /名称> < > 69岁年龄< / > < > /人EOF;$序列化器->反序列化($数据,“Acme \人”,“xml”,数组(“object_to_populate”= >$人));// $person = Acme\ person(名字:'foo',年龄:'69',运动员:true)
这是使用ORM时的一个常见需求。
属性组
有时,您希望序列化来自实体的不同属性集。分组是实现这一需求的便捷方式。
假设你有以下简单的老php对象:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
名称空间Acme;类MyObj{公共$喷火;私人$酒吧;公共函数getBar(){返回$这->酒吧;}公共函数setBar($酒吧){返回$这->酒吧=$酒吧;}}
序列化的定义可以使用注释、XML或YAML来指定。的ClassMetadataFactory归一化器将使用的对象必须知道要使用的格式。
初始化ClassMetadataFactory像下面这样:
12 3 4 5 6 7 8 9 10 11 12 13 14
使用欧宝娱乐app下载地址\组件\序列化器\映射\工厂\ClassMetadataFactory;//对于注释使用学说\常见的\注释\AnnotationReader;使用欧宝娱乐app下载地址\组件\序列化器\映射\加载程序\AnnotationLoader;//用于XML//使用Sym欧宝娱乐app下载地址fony\Component\Serializer\Mapping\Loader\XmlFileLoader;//对于YAML//使用Sym欧宝娱乐app下载地址fony\Component\Serializer\Mapping\Loader\YamlFileLoader;$classMetadataFactory=新ClassMetadataFactory (新AnnotationLoader (新AnnotationReader ()));//用于XML// $classMetadataFactory = new classMetadataFactory (new XmlFileLoader('/path/to/your/ define .xml'));//对于YAML$classMetadataFactory = new classMetadataFactory (new YamlFileLoader('/path/to/your/ define .yml'));
然后,创建你的组定义:
- 注释
- YAML
- XML
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
名称空间Acme;使用欧宝娱乐app下载地址\组件\序列化器\注释\组;类MyObj{/ * * *@Groups({"group1", "group2"}) */公共$喷火;/ * * *@Groups({}“group3”)* /公共函数getBar()//是*方法是也支持{返回$这->酒吧;}/ /……}
你现在只能序列化你想要的组中的属性:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
使用欧宝娱乐app下载地址\组件\序列化器\序列化器;使用欧宝娱乐app下载地址\组件\序列化器\标准化者\ObjectNormalizer;$obj=新MyObj ();$obj->foo =“foo”;$obj->setBar (“酒吧”);$标准化者=新ObjectNormalizer ($classMetadataFactory);$序列化器=新序列化器(数组($标准化者));$数据=$序列化器->正常化($obj,零,数组(“组织”= >数组(“group1”)));// $data = array('foo' => 'foo');$methoda=$序列化器->denormalize (数组(“foo”= >“foo”,“酒吧”= >“酒吧”),“MyObj”,零,数组(“组织”= >数组(“group1”,“group3”)));// $obj2 = MyObj(foo: 'foo', bar: 'bar')
忽略属性
请注意
属性组代替setIgnoredAttributes ()方法被认为是最佳实践。
作为一个选项,有一种方法可以忽略来自源对象的属性。要删除这些属性,请使用setIgnoredAttributes ()方法的规范化定义:
1 2 3 4 5 6 7 8 9 10
使用欧宝娱乐app下载地址\组件\序列化器\序列化器;使用欧宝娱乐app下载地址\组件\序列化器\编码器\JsonEncoder;使用欧宝娱乐app下载地址\组件\序列化器\标准化者\ObjectNormalizer;$标准化者=新ObjectNormalizer ();$标准化者->setIgnoredAttributes (数组(“年龄”));$编码器=新JsonEncoder ();$序列化器=新序列化器(数组($标准化者),数组($编码器));$序列化器->序列化($人,json的);//输出:{"name":"foo","sportsman":false}
在序列化和反序列化时转换属性名
有时序列化属性的命名必须与PHP类的属性或getter/setter方法不同。
Serializer组件提供了一种方便的方法来将PHP字段名转换或映射到序列化的名称:名称转换系统。
假设你有以下对象:
1 2 3 4 5
类公司{公共$的名字;公共$地址;}
在序列化形式中,所有属性都必须以org_
像下面这样:
1
{“org_name”:“Acme公司。”,“org_address”:“大城市主街123号”}
自定义名称转换器可以处理以下情况:
12 3 4 5 6 7 8 9 10 11 12 13 14 15
使用欧宝娱乐app下载地址\组件\序列化器\NameConverter\NameConverterInterface;类OrgPrefixNameConverter实现了NameConverterInterface{公共函数正常化($propertyName){返回“org_”.$propertyName;}公共函数denormalize($propertyName){//删除前缀返回“org_”= = = substr ($propertyName,0,4) ?substr ($propertyName,4):$propertyName;}}
自定义规范化器可以通过将其作为任何类扩展的第二个参数来使用AbstractNormalizer,包括GetSetMethodNormalizer而且PropertyNormalizer:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
使用欧宝娱乐app下载地址\组件\序列化器\编码器\JsonEncoder使用欧宝娱乐app下载地址\组件\序列化器\标准化者\ObjectNormalizer;使用欧宝娱乐app下载地址\组件\序列化器\序列化器;$nameConverter=新OrgPrefixNameConverter ();$标准化者=新ObjectNormalizer (零,$nameConverter);$序列化器=新序列化器(数组($标准化者),数组(新JsonEncoder ()));$obj=新公司();$obj->name =“Acme公司”。;$obj->地址=“大城市主街123号”;$json=$序列化器->序列化($obj);// {"org_name": "Acme Inc.", "org_address": "大城市主街123号"}$objCopy=$序列化器->反序列化($json);//与$obj相同的数据
CamelCase到snake_case
在许多格式中,通常使用下划线分隔单词(也称为snake_case)。但是,PSR-1指定PHP属性和方法的首选样式是CamelCase。
欧宝娱乐app下载地址Symfony提供了一个内置的名称转换器,设计用于在序列化和反序列化过程中在snake_case和camelcases样式之间转换:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
使用欧宝娱乐app下载地址\组件\序列化器\NameConverter\CamelCaseToSnakeCaseNameConverter;使用欧宝娱乐app下载地址\组件\序列化器\标准化者\ObjectNormalizer;$标准化者=新ObjectNormalizer (零,新CamelCaseToSnakeCaseNameConverter ());类人{私人$firstName;公共函数__construct($firstName){$这->firstName =$firstName;}公共函数getFirstName(){返回$这->firstName;}}$凯文=新人(“凯文”);$标准化者->正常化($凯文);// ['first_name' => 'Kévin'];$安妮=$标准化者->denormalize (数组(“first_name”= >“安妮”),“人”);// firstName: 'Anne'的Person对象
序列化布尔属性
如果您正在使用isser方法(方法前缀为是
,就像Acme \人::isSportsman ()
), Serializer组件将自动检测并使用它来序列化相关属性。
的ObjectNormalizer
还关心从。开始的方法有
,添加
而且删除
.
使用回调序列化对象实例的属性
当序列化时,你可以设置一个回调来格式化一个特定的对象属性:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
使用Acme\人;使用欧宝娱乐app下载地址\组件\序列化器\编码器\JsonEncoder;使用欧宝娱乐app下载地址\组件\序列化器\标准化者\GetSetMethodNormalizer;使用欧宝娱乐app下载地址\组件\序列化器\序列化器;$编码器=新JsonEncoder ();$标准化者=新GetSetMethodNormalizer ();$回调=函数($dateTime){返回$dateTime运算符\ DateTime吗?$dateTime->(\ DateTime格式::ISO8601):”;};$标准化者->setCallbacks (数组(“createdAt”= >$回调));$序列化器=新序列化器(数组($标准化者),数组($编码器));$人=新人();$人->setName (“cordoval”);$人->setAge (34);$人->setCreatedAt (新\ DateTime (“现在”));$序列化器->序列化($人,json的);/ /输出:{“名称”:“cordoval”,“年龄”:34岁“createdAt”:“2014 - 03 - 22 - t09:43:12 - 0500 "}
标准化者
有几种类型的归一化器可用:
- ObjectNormalizer
-
这个归一化器利用PropertyAccess组件在对象中读写。这意味着它可以直接访问属性,并通过getter, setter, hassers, adder和removers。它支持在反规格化过程中调用构造函数。
对象被规范化为属性名(方法名去掉“get”/“set”/“has”/“remove”前缀并转换为小写)到属性值的映射。
的
ObjectNormalizer
是最强大的归一化器。它是在使用启用序列化器的Symfony标准版时默认配置的。欧宝娱乐app下载地址 - GetSetMethodNormalizer
-
这个规范化器通过调用“getter”(以“get”开头的公共方法)来读取类的内容。它将通过调用构造函数和“setter”(以“set”开头的公共方法)来反规范化数据。
对象被规范化为属性名(方法名去掉“get”前缀并转换为小写)到属性值的映射。
- PropertyNormalizer
-
此规范化器直接读取和写入公共属性以及私人和受保护的属性。它支持在反规格化过程中调用构造函数。
对象被规范化为属性名到属性值的映射。
处理循环引用
循环引用在处理实体关系时很常见:
12 34 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
类组织{私人$的名字;私人$成员;公共函数setName($的名字){$这->name =$的名字;}公共函数getName(){返回$这->名称;}公共函数setMembers(数组$成员){$这->成员=$成员;}公共函数getMembers(){返回$这->成员;}}类成员{私人$的名字;私人$组织;公共函数setName($的名字){$这->name =$的名字;}公共函数getName(){返回$这->名称;}公共函数setOrganization(组织$组织){$这->组织=$组织;}公共函数getOrganization(){返回$这->组织;}}
为了避免无限循环,GetSetMethodNormalizer抛出一个CircularReferenceException遇到这种情况时:
1 2 3 4 5 6 7 8 9 10
$成员=新成员();$成员->setName (“凯文”);$org=新组织();$org->setName (“Les-Tilleuls.coop”);$org->setMembers (数组($成员));$成员->setOrganization ($org);回声$序列化器->序列化($org,json的);//抛出CircularReferenceException
的setCircularReferenceLimit ()
方法设置在将同一对象视为循环引用之前序列化该对象的次数。默认值为1
.
循环引用也可以由自定义调用对象处理,而不是抛出异常。这在序列化具有唯一标识符的实体时特别有用:
1 2 3 4 5 6 7 8 9 10
$编码器=新JsonEncoder ();$标准化者=新ObjectNormalizer ();$标准化者->setCircularReferenceHandler (函数($对象){返回$对象->getName ();});$序列化器=新序列化器(数组($标准化者),数组($编码器));var_dump ($序列化器->序列化($org,json的));/ / {" name ": " Les-Tilleuls。coop","members":[{"name":"K\u00e9vin",组织:" Les-Tilleuls.coop"}]}
处理数组
Serializer组件也能够处理对象数组。序列化数组就像序列化单个对象一样:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
使用Acme\人;$person1=新人();$person1->setName (“foo”);$person1->setAge (99);$person1->setSportsman (假);$person2=新人();$person2->setName (“酒吧”);$person2->setAge (33);$person2->setSportsman (真正的);$人=数组($person1,$person2);$数据=$序列化器->序列化($人,json的);/ /数据包含美元[{“名称”:“foo”,“年龄”:99年,“运动员”:假},{“名称”:“酒吧”,“年龄”:33岁的“运动员”:真正}]
如果要反序列化这样的结构,需要添加ArrayDenormalizer归一化函数的集合。通过添加[]
属性的类型参数反序列化()方法,则表明您期待的是一个数组,而不是单个对象。
12 3 4 5 6 7 8 9 10 11 12
使用欧宝娱乐app下载地址\组件\序列化器\编码器\JsonEncoder;使用欧宝娱乐app下载地址\组件\序列化器\标准化者\ArrayDenormalizer;使用欧宝娱乐app下载地址\组件\序列化器\标准化者\GetSetMethodNormalizer;使用欧宝娱乐app下载地址\组件\序列化器\序列化器;$序列化器=新序列化器(数组(新GetSetMethodNormalizer (),新ArrayDenormalizer ()),数组(新JsonEncoder ()));$数据=……;//前面示例中的序列化数据$人=$序列化器->反序列化($数据,“Acme \[]的人”,json的);
另请参阅
Symfony Serializer Component的欧宝娱乐app下载地址一个流行替代品是第三方库,JMS序列化器(在Apache许可证下发布,因此与GPLv2项目不兼容)。