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

posted @ 2023-07-26 21:34  x3d  阅读(101)  评论(0编辑  收藏  举报