darsyn/unboxer

简单的工具,将复杂的数据结构(对象)转换为原生数据类型,适合编码成JSON、YAML等格式。

0.3.1 2021-03-09 12:28 UTC

This package is auto-updated.

Last update: 2024-09-09 20:10:04 UTC


README

简单的工具,将复杂的数据结构(对象)转换为原生数据类型,适合编码(例如,JSON)。

文档

行为准则

本项目包含并遵守贡献者公约作为行为准则。

支持的类型

此库将所有标量和null值按原样返回,并递归处理所有数组(和stdClass)类型。

当此库遇到已知类型的对象实例时,它将尝试通过使用特定方法的返回值来转换它。此库默认支持的对象类型包括

  • 日期(实现DateTimeInterface的对象),根据RFC3339转换为字符串(例如,2019-02-05T12:15:32+00:00)。
  • 时区(实现DateTimeZone的对象),结果是包含时区名称的字符串(例如,America/Vancouver)。
  • 异常和错误(实现Throwable的对象),结果是包含异常信息的字符串。
  • JSON(实现JsonSerializable的对象),结果是库递归遍历返回的JSON数据。
  • Doctrine集合(实现Collection接口的对象),结果是库遍历集合中的每个项目。

此外,任何用户空间对象都可以实现UnboxableInterface。类似于JsonSerializable::jsonSerialize()方法,__unbox方法可以返回表示其内部状态的任何内容。建议按原样返回可解包的对象,因为从UnboxableInterface::__unbox返回的任何内容都将递归遍历。

简要示例

<?php declare(strict_types=1);

use Darsyn\Unboxer\Unboxer;
use Darsyn\Unboxer\UnboxableInterface;
use Darsyn\Unboxer\UnboxingException;

class Group implements UnboxableInterface {
    public function __construct(
        private string $name
    ) {}

    public function __unbox() {
        return $this->name;
    }
}

class Options implements \JsonSerializable {
    public function __construct(
        private bool $active,
        private bool $verified,
        private \DateTimeZone $timezone
    ) {}

    public function jsonSerialize() {
        return [
            'active' => $this->active,
            'verified' => $this->verified,
            'tz' => $this->timezone,
        ];
    }
}

class Member implements UnboxableInterface
{
    private ArrayCollection $groups;

    public function __construct(
        private int $id,
        private string $username,
        array $groups = [],
        private ?Options $options = null
    ) {
        $this->groups = new ArrayCollection($groups);
    }

    public function __unbox()
    {
        return [
            // Scalars are used as-is.
            'id' => $this->id,
            'username' => $this->username,
            // Objects of known types are returned as-is, but recursively iterated over.
            'groups' => $this->groups,
            // JSON-serializable objects are never actually run through json_encode().
            'options' => $this->options ?: [],
        ];
    }
}

$member = new Member(123, 'dr-evil', [
    new Group('admin'),
    new Group('moderator'),
    new Group('sharks-with-lasers'),
], new Options(true, false, new \DateTimeZone('America/Vancouver')));

try {
    $output = (new Unboxer)->unbox($member);
    var_dump($output);
} catch (UnboxingException $e) {
    echo $e->getMessage();
}

使用var_dump变量$output的结果是

array(4) {
  'id' =>
  int(123)
  'username' =>
  string(7) "dr-evil"
  'groups' =>
  array(3) {
    [0] =>
    string(5) "admin"
    [1] =>
    string(9) "moderator"
    [2] =>
    string(18) "sharks-with-lasers"
  }
  'options' =>
  array(3) {
    'active' =>
    bool(true)
    'verified' =>
    bool(false)
    'tz' =>
    string(17) "America/Vancouver"
  }
}

注意,返回多个嵌套的可解包对象会导致输出折叠为单个值

<?php declare(strict_types=1);

use Darsyn\Unboxer\Unboxer;
use Darsyn\Unboxer\UnboxableInterface;
use Darsyn\Unboxer\UnboxingException;

$data = new class implements UnboxableInterface {
    public function __unbox() {
        return new class implements UnboxableInterface {
            public function __unbox() {
                return new class implements UnboxableInterface {
                    public function __unbox() {
                        return new \RuntimeException('Error Message');
                    }
                };
            }
        };
    }
};

try {
    $output = (new Unboxer)->unbox($data);
    var_dump($output);
} catch (UnboxingException $e) {
    echo $e->getMessage();
}
string(13) "Error Message"

扩展

可以通过扩展Unboxer并重写getKnownDataTypes方法来添加额外的已知对象类型。对于每个已知对象类型,可以指定一个闭包或一个数组,指定在对象上调用哪个方法

<?php declare(strict_types=1);

use Darsyn\Unboxer\Unboxer;

class MyUnboxer extends Unboxer {
    protected function getKnownDataMethods(): iterable {
        // Don't forget to return the known data methods defined in the original, parent Unboxer.
        // The parent returns an array, but any iterable is acceptable.
        yield from parent::getKnownDataMethods();

        // Config array example.
        // Must be in the format ['methodToCall', ['optional', 'arguments', 'array']].
        yield \DateTimeInterface::class => ['format', [\DateTimeInterface::RFC3339]];

        // Closure example.
        yield \DateTimeInterface::class => function (\DateTimeInterface $date): string {
            return $date->format(\DateTimeInterface::RFC3339);
        };
    }
}

默认情况下,解包器将具有__toString()魔法方法的任何对象转换为字符串。要关闭此功能,扩展Unboxer并重写类常量STRINGIFY_OBJECTS

<?php declare(strict_types=1);

use Darsyn\Unboxer\Unboxer;

class MyUnboxer extends Unboxer {
    public const STRINGIFY_OBJECTS = false;
}

许可证

请参阅此存储库中包含的单独的许可证文件,其中包含完整的MIT许可证副本,本项目受此许可证许可。

作者

如果您做出贡献(提交拉取请求),请别忘了在此处添加您的名字!