waibelp/yamlizer

Yamlizer 是一个关注简洁性和性能的 PHP 对象序列化工具。

v0.6 2016-12-05 20:39 UTC

This package is not auto-updated.

Last update: 2024-09-18 19:07:06 UTC


README

Build Status

Yamlizer 是一个关注简洁性和性能的 PHP 对象序列化工具。

它支持

  • 将 PHP 对象序列化到数组结构中,可以将其转储为 JSON、YAML 等
  • 将数组结构对象反序列化为 PHP 对象
  • 所有标量数据类型、数组、对象数组,甚至 \DateTime 实例
  • 易于使用的注解来控制序列化和反序列化行为,如可空属性、组等
  • 缓存类和属性元数据 - 运行时无缓慢的反射或注解解析

安装

使用 composer 在项目中要求并安装库

$ composer require waibelp/yamlizer

使用

向类添加注解以使其可序列化

namespace Acme\Entity;

use Acme\Entity\SomeOtherEntity;
use Yamlizer\Annotation\Type;

class FooBarEntity
{
    /**
     * @Type("string")
     * @var string
     */
    protected $scalarProperty = 'This is a string';
    
    /**
     * @Type("array")
     * @var array
     */
    protected $arrayProperty = [1, 2, 3];
    
    /**
     * @Type("Acme\Entity\SomeOtherEntity")
     * @var SomeOtherEntity
     */
    protected $fixedTypeProperty;
    
    /**
     * @Type("array<Acme\Entity\SomeOtherEntity>")
     * @var SomeOtherEntity[]
     */
    protected $fixedTypeList = [];
    
    /**
     * Return value of scalarProperty. Getter methods name uppercases the first letter of the property name and prepends get.
     *
     * @return string
     */
    public function getScalarProperty()
    {
        return $this->scalarProperty;
    }
    
    /**
     * Set value for scalarProperty. Setter methods name uppercases the first letter of the property name and prepends set.
     *
     * @var string $scalarProperty
     */
    public function setScalarProperty($scalarProperty)
    {
        $this->scalarProperty = $scalarProperty;
    }

    // Other getter and setter methods...
}

实例化并使用 ArraySerializer 来序列化我们的对象

use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Yaml\Yaml;
use Yamlizer\Metadata\MetadataFactory;
use Yamlizer\Serialization\ArraySerializer;

$metadataFactory = new MetadataFactory(new AnnotationReader());
$arraySerializer = new ArraySerializer($metadataFactory);

$object           = new FooBarEntity();
$serializedObject = $arraySerializer->serialize($object, FooBarEntity::class);

print gettype($serializedObject); // array
$json = json_encode($serializedObject);
$yaml = Yaml::dump($serializedObject);

输出 $yaml 结果为

scalarProperty: "This is a string"
arrayProperty:
    - 1
    - 2
    - 3
fixedTypeProperty: null
fixedTypeList: []

输出 $json 结果为

{
    "scalarProperty": "This is a string",
    "arrayProperty": [1, 2, 3],
    "fixedTypeProperty": null,
    "fixedTypeList": []
}

然后再反序列化它

use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\Yaml\Yaml;
use Yamlizer\Metadata\MetadataFactory;
use Yamlizer\Serialization\ArrayDeserializer;

$metadataFactory = new MetadataFactory(new AnnotationReader());
$arraySerializer = new ArrayDeserializer($metadataFactory);

/** @var FooBarEntity $object */
$array  = json_decode($json, true); // or Yaml::parse($yaml);
$object = $arrayDeserializer->deserialize($array, FooBarEntity:class);

注解列表

类型(string)

定义了给定属性的 data 类型。可能是 PHP 的标量类型或包含命名空间的完全限定类名。

use Yamlizer\Annotation\Type;

class AcmeEntity
{
    /**
     * @Type("string")
     * @var string
     */
    protected $someString = 'This is just some string';

    /**
     * Always define format of date time string! Supports PHPs datetime format syntax.
     *
     * @Type("\DateTime<Y-m-d H:i:s>")
     * @var \DateTime
     */
    protected $dateTime;
}

$object = new AcmeEntity();
$object->setDateTime(new \DateTime('2016-26-01 01:02:03'));

// Serialization results in
// {"someString": "This is just some string", "dateTime": "2016-26-01 01:02:03"}

有效类型

SerializedName(string)

定义了序列化属性的名称。如果没有定义,则使用属性名称。

use Yamlizer\Annotation\SerializedName;

class AcmeEntity
{
    /**
     * @SerializedName("entities")
     * @var Acme\Entity\SomeSpecialEntity[]
     */
    protected $specialEntities = [];
}

// Serialization results in
// {"entities": []}

GetterName(string)

定义了获取属性值的 getter 方法名称。默认命名策略将属性名称的首字母大写并前置 get。

use Yamlizer\Annotation\GetterName;
use Yamlizer\Annotation\Type;

class AcmeEntity
{
    /**
     * @Type("string")
     * @GetterName("computeSomeString")
     * @var string
     */
    protected $someString = 'string';
    
    public function computeSomeString()
    {
        return 'Awesome ' . $this->someString;
    }
}

SetterName(string)

定义了设置属性值的 setter 方法名称。默认命名策略将属性名称的首字母大写并前置 set。

use Yamlizer\Annotation\Type;
use Yamlizer\Annotation\SetterName;

class AcmeEntity
{
    /**
     * @Type("string")
     * @SetterName("setString")
     * @var string
     */
    protected $someString = 'string';
    
    /**
     * @var string $string
     */
    public function setString($string)
    {
        $this->someString = $string;
    }
}

Nullable(boolean)

属性是否可空。在反序列化 null 值时抛出 NullValueException。默认为 true。

use Yamlizer\Annotation\Nullable;

class AcmeEntity
{
    /**
     * @Type("array<Acme\Entity\SomeSpecialEntity>")
     * @Nullable(false)
     * @var Acme\Entity\SomeSpecialEntity[]
     */
    protected $specialEntity = [];
}

Readonly(boolean)

属性是否只读。不会将值反序列化到只读属性中。默认为 false。

use Yamlizer\Annotation\Readonly;

class AcmeEntity
{
    /**
     * @Readonly(true)
     * @var Acme\Entity\SomeSpecialEntity[]
     */
    protected $specialEntity = [];
}

PreserveKeys(boolean)

仅影响数组。在序列化期间是否保留数组键或丢弃它们。

use Yamlizer\Annotation\PreserveKeys;

class AcmeEntity
{
    /**
     * @PreserveKeys(true)
     * @var array
     */
    protected $myArray = [
        'one' => 1,
        'two' => 2,
    ];
}

Groups(string[])

每个属性可以分配一个或多个组,这些组可用于控制序列化和反序列化期间映射的属性。

use Yamlizer\Annotation\Groups;

class AcmeEntity
{
    /**
     * @Groups("a, b")
     * @var int
     */
    protected $integerOne = 1;
    
    /**
     * @Groups("a")
     * @var int
     */
    protected $integerTwo = 2;
}

高级主题

使用组来控制要序列化和反序列化的属性

想象一个具有不同组属性的对象

class GroupEntity
{
    /**
     * @Type("integer")
     * @Groups("odd, all")
     * @var int
     */
    protected $one = 1;

    /**
     * @Type("integer")
     * @Groups("even, all")
     * @var int
     */
    protected $two = 2;

    /**
     * @Type("integer")
     * @Groups("odd, all")
     * @var int
     */
    protected $three = 3;

    /**
     * @Type("integer")
     * @Groups("even, all")
     * @var int
     */
    protected $four = 4;

现在只需设置我们的 Context 对象以设置类的组

use Doctrine\Common\Annotations\AnnotationReader;
use Yamlizer\Metadata\MetadataFactory;
use Yamlizer\Metadata\ClassMetadata;
use Yamlizer\Serialization\ArraySerializer;
use Yamlizer\Serialization\Context;

$metadataFactory = new MetadataFactory(new AnnotationReader());
$arraySerializer = new ArraySerializer($metadataFactory);

$context = new Context();
$object  = new GroupEntity();

// Having no groups set results in all properties
var_dump($arraySerializer->serialize($object, GroupEntity::class, $context)); // ['one' => 1, 'two' => 2, 'three' => 3, 'four' => 4]

// Skip all properties not in group even
$context->setGroups(GroupEntity::class, ['even']);
var_dump($arraySerializer->serialize($object, GroupEntity::class, $context)); // ['two' => 2, 'four' => 4]

// Skip all properties not in group odd
$context->setGroups(GroupEntity::class, ['odd']);
var_dump($arraySerializer->serialize($object, GroupEntity::class, $context)); // ['one' => 1, 'three' => 3]

缓存

Yamlizer 附带了两个缓存:InMemoryCacheFileCache

use Doctrine\Common\Annotations\AnnotationReader;
use Yamlizer\Cache\FileCache;
use Yamlizer\Cache\InMemoryCache;
use Yamlizer\Metadata\MetadataFactory;
use Yamlizer\Metadata\ClassMetadata;
use Yamlizer\Serialization\ArraySerializer;

$metadataFactory = new MetadataFactory(new AnnotationReader());
$arraySerializer = new ArraySerializer($metadataFactory);

$cacheDirectoryPath = __DIR__ . '/some/writeable/cache/directory';
$arraySerializer->addCache(new InMemoryCache());
$arraySerializer->addCache(new FileCache($cacheDirectoryPath));

异常

将对象序列化为数据并相反总会在数据错误或缺失的情况下抛出异常。

要捕获这些异常,只需将调用包装在 try-catch 块中

use Yamlizer\Exception\InvalidTypeException;
use Yamlizer\Exception\NullValueException;
use Yamlizer\Exception\YamlizerException;

$metadataFactory = new MetadataFactory(new AnnotationReader());
$arraySerializer = new ArraySerializer($metadataFactory);
// ...

try {
    $arraySerializer->serialize($object);
} catch (NullValueException $e1) {
    // Catch exceptions caused by null values
} catch (InvalidTypeException $e2) {
    // Catch exceptions caused by invalid types
} catch (YamlizerException $e3) {
    // Fetch all kinds of exceptions thrown from Yamlizer package
}

贡献

  1. 叉取仓库并实现修复
  2. 扩展测试并用 bin/phpunit 验证
  3. 检查代码覆盖率 tests/build/report/index.html
  4. 检查代码风格 bin/phpcs --standard=PSR2 src/
  5. 提交拉取请求