apie/type-converter

将对象从特定类型转换为其他类型。

1.3.1 2024-02-02 14:05 UTC

This package is auto-updated.

Last update: 2024-10-01 00:09:14 UTC


README

Apie 类型转换器

Latest Stable Version Total Downloads Latest Unstable Version License PHP Version Require Code coverage Donate

Apie 是一套用于处理领域对象的 composer 包。它试图采用以领域对象为先的方法,而不是像现在许多 PHP 框架中所找到的以数据库为先的方法。

此类型转换器包在 monorepo 外编写,提供了一种简单的工具来将对象转换为其他对象。

使用方法

最简单的用法

<?php
use Apie\TypeConverter\DefaultConvertersFactory;
$converter = DefaultConvertersFactory::create();
var_dump($converter->convertTo(12, 'string')); // '12'

这不是一个非常有用的示例。通常您会尝试将 DTO 转换为领域对象或相反。

更复杂的示例

<?php
use Apie\TypeConverter\DefaultConvertersFactory;

class Dto {
    public string $description;

    public string $name;
}

class DomainObject {
    public function __construct(
        private string $description,
        private string $name
    ) {
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getDescription(): string
    {
        return $this->description;
    }
}
use Apie\TypeConverter\DefaultConvertersFactory;
$converter = DefaultConvertersFactory::create();
$dto = ($converter->convertTo(new DomainObject('description', 'name'), Dto::class));
var_dump($dto->name); // 'name'
$converter->convertTo($dto, DomainObject::class);

创建自己的转换器

创建自己的转换器非常简单。您只需创建一个实现 ConverterInterface 的类。如果您使用 phpstan 进行静态代码分析,可以添加一个小小的 phpdoc 来帮助 phpstan 理解类型转换。

<?php
use Apie\Core\ValueObjects\Interfaces\StringValueObjectInterface;
use Apie\TypeConverter\ConverterInterface;

/**
 * @implements ConverterInterface<StringValueObjectInterface, string>
 */
class StringValueObjectToStringConverter implements ConverterInterface
{
    public function convert(StringValueObjectInterface $valueObject): string
    {
        return $valueObject->toNative();
    }
}

use Apie\TypeConverter\DefaultConvertersFactory;
$converter = DefaultConvertersFactory::create(new StringValueObjectToStringConverter());
$converter->convertTo(new Email('test@example.com'), 'string');

自定义 TypeConverter

DefaultConvertsFactory 创建一个具有合理默认值的 TypeConverter 实例。您可以通过调用构造函数来配置所有内容。请记住,所有默认转换器也需要手动添加。

<?php
use Apie\TypeConverter\Converters\FloatToStringConverter;
use Apie\TypeConverter\Converters\IntToStringConverter;
use Apie\TypeConverter\Converters\ObjectToObjectConverter;
use Apie\TypeConverter\TypeConverter;
$converter = new TypeConverter(
    new ObjectToObjectConverter(),
    new IntToStringConverter(),
    new FloatToStringConverter()
);

复杂的转换器

在上面的示例中,我们可以将字符串值对象转换为字符串,但如何将其转换回原来的类型呢?

我们可以为每个值对象创建一个转换器,但这将意味着许多类似的类。

<?php
use Apie\Core\ValueObjects\Interfaces\StringValueObjectInterface;
use Apie\TypeConverter\ConverterInterface;

/**
 * @implements ConverterInterface<string, Email>
 */
class StringToEmailConverter implements ConverterInterface
{
    public function convert(string $value): Email
    {
        return Email::fromNative($value);
    }
}

幸运的是,我们可以通过提供所需的类型作为第二个参数来提供一个更好的解决方案。

<?php
use Apie\Core\ValueObjects\Interfaces\StringValueObjectInterface;
use Apie\TypeConverter\ConverterInterface;

/**
 * @implements ConverterInterface<string, StringValueObjectInterface>
 */
class StringToStringValueObjectConverter implements ConverterInterface
{
    public function convert(string $value, \ReflectionNamedType $wantedType): StringValueObjectInterface
    {
        $className = $wantedType->getName();
        return $className::fromNative($value);
    }
}

还可以获取 TypeConverter 实例以进行递归转换。

<?php
use Apie\Core\ValueObjects\Interfaces\StringValueObjectInterface;
use Apie\TypeConverter\ConverterInterface;
use Apie\TypeConverter\TypeConverter;

/**
 * @implements ConverterInterface<int, StringValueObjectInterface>
 */
class IntToStringValueObjectConverter implements ConverterInterface
{
    public function convert(int $value, \ReflectionNamedType $wantedType, TypeConverter $typeConverter): StringValueObjectInterface
    {
        $value = $typeConverter->convertTo($value, 'string');
        $className = $wantedType->getName();
        return $className::fromNative($value);
    }
}

转换器优先级

如果有多个转换器可以执行转换,则最准确的转换器将具有优先权。

<?php
use Apie\TypeConverter\Converters\FloatToStringConverter;
use Apie\TypeConverter\Converters\IntToStringConverter;
use Apie\TypeConverter\Converters\ObjectToObjectConverter;
use Apie\TypeConverter\TypeConverter;
$converter = new TypeConverter(
    new ObjectToObjectConverter(),
    new IntToStringConverter(),
    new FloatToStringConverter()
);

如果我要尝试将 '1' 转换为 IntToStringConverter,则 IntToStringConverter 和 FloatToStringConverter 都适用,但由于 int 类型更准确,因此它使用 IntToStringConverter。