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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章