PHP 中优雅的将JSON/XML/YAML 等数据反序列化成指定的类对象
这个小事情何以需要记上一笔?实在是因为当用了各种编程语言以后,发现系统 I/O处,尤其对外的接口Interface最重要,它或许可以被称为 Specification ,规约。
PHP 是混合型编程风格的语言,不强求完全的OOP。但是代码不OOP化的话,又得不到更多的开发工具的支持。尤其在PHP中如果只是用数组结构处理这种 接口处的强spec场景,在Editor/IDE中的代码就很难达到易读性(不便于它们理解,也就不便于人理解)。
因此以前在很多项目中,会尝试手动做这样的对象化的结构转换,将接收到的请求报文,映射成一个预先定义了清晰结构的Class实例化对象上。这个过程,专业叫法应该叫 “序列化/反序列化(serialize / unserialize)”。多数编程语言都有相应的内置的方法,PHP也有。
这种序列化反序列化,狭义的讲法,是指编程语言级别的算法。不过我们面临的不仅仅是这种情况,甚至更多的不是这种情况,框架会在底层解决掉,应用中往往都很少意识到。更多的情况是跨系统间的数据结构的序列化,比如XML<=> Java/PHP/...、以及当前更主流的 JSON <=> Java/PHP/...
像多数有点年岁的编程语言比如Java一样,PHP 也不太可能原生支持 JSON 类型,最多类型化为对象式访问结构,当然PHP中可以直接decode(某种“反序列化”)为更原生的数组结构或者stdclass(像是某种匿名类对象)。如前所述,这种过程在实际应用开发中,是非常重要的涉及系统稳定性维护的环节。
因此,严肃认真的人会系统性的去研究,并实现解决方案,比如 Symfony/Serializer 组件。
The Serializer component is meant to be used to turn objects into a specific format (XML, JSON, YAML, ...) and the other way around.
原理倒还是以 PHP的 数组为中介,进行两个方向的转换,
它将序列化的过程拆解成了两个子过程,encode/decode;normalize/denoralize 。
示意图如下:
安装:
composer require symfony/serializer`
用法:
比如预先定义一个对象结构:
class Person
{
private int $age;
private string $name;
private bool $sportsperson;
private ?\DateTimeInterface $createdAt;
// Getters
public function getAge(): int
{
return $this->age;
}
public function getName(): string
{
return $this->name;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
// Issers
public function isSportsperson(): bool
{
return $this->sportsperson;
}
// Setters
public function setAge(int $age): void
{
$this->age = $age;
}
public function setName(string $name): void
{
$this->name = $name;
}
public function setSportsperson(bool $sportsperson): void
{
$this->sportsperson = $sportsperson;
}
public function setCreatedAt(\DateTimeInterface $createdAt = null): void
{
$this->createdAt = $createdAt;
}
}
然后就可以从其它数据源如xml来反序列化成对象。
use App\Model\Person;
$data = <<<EOF
<person>
<name>foo</name>
<age>99</age>
<sportsperson>false</sportsperson>
</person>
EOF;
$person = $serializer->deserialize($data, Person::class, 'xml');
有更多高级用法,详见:https://symfony.com/doc/current/components/serializer.html