跳至正文

更新日志 1.12.0 — 2024 年 4 月 4 日

重要变更

引入非密封指定结构的数组语法

此语法通过允许必须遵循特定类型的附加值来实现指定结构的数组类型的扩展。

$mapper = (new \CuyZ\Valinor\MapperBuilder())->mapper();

// Default syntax can be used like this:
$mapper->map(
    'array{foo: string, ...array<string>}',
    [
        'foo' => 'foo',
        'bar' => 'bar', // ✅ valid additional value
    ]
);

$mapper->map(
    'array{foo: string, ...array<string>}',
    [
        'foo' => 'foo',
        'bar' => 1337, // ❌ invalid value 1337
    ]
);

// Key type can be added as well:
$mapper->map(
    'array{foo: string, ...array<int, string>}',
    [
        'foo' => 'foo',
        42 => 'bar', // ✅ valid additional key
    ]
);

$mapper->map(
    'array{foo: string, ...array<int, string>}',
    [
        'foo' => 'foo',
        'bar' => 'bar' // ❌ invalid key
    ]
);

// Advanced types can be used:
$mapper->map(
    "array{
        'en_US': non-empty-string,
        ...array<non-empty-string, non-empty-string>
    }",
    [
        'en_US' => 'Hello',
        'fr_FR' => 'Salut', // ✅ valid additional value
    ]
);

$mapper->map(
    "array{
        'en_US': non-empty-string,
        ...array<non-empty-string, non-empty-string>
    }",
    [
        'en_US' => 'Hello',
        'fr_FR' => '', // ❌ invalid value
    ]
);

// If the permissive type is enabled, the following will work:
(new \CuyZ\Valinor\MapperBuilder())
    ->allowPermissiveTypes()
    ->mapper()
    ->map(
        'array{foo: string, ...}',
        ['foo' => 'foo', 'bar' => 'bar', 42 => 1337]
    ); // ✅

接口构造函数注册

默认情况下,映射器无法实例化接口,因为它不知道要使用哪个实现。为此,可以使用MapperBuilder::infer()方法,但在大多数情况下很麻烦。

现在还可以为接口注册构造函数,就像为类注册构造函数一样。

由于映射器无法自动猜测接口可以使用哪个实现,因此无法使用Constructor特性,必须使用MapperBuilder::registerConstructor()方法。

在下面的示例中,映射器被教导如何从包ramsey/uuid实例化UuidInterface的实现:

(new \CuyZ\Valinor\MapperBuilder())
    ->registerConstructor(
        // The static method below has return type `UuidInterface`;
        // therefore, the mapper will build an instance of `Uuid` when
        // it needs to instantiate an implementation of `UuidInterface`.
        Ramsey\Uuid\Uuid::fromString(...)
    )
    ->mapper()
    ->map(
        Ramsey\Uuid\UuidInterface::class,
        '663bafbf-c3b5-4336-b27f-1796be8554e0'
    );

JSON 规范化器格式选项

默认情况下,JSON 规范化器将仅使用JSON_THROW_ON_ERROR来编码非布尔标量值。在某些用例中,项目可能需要诸如JSON_JSON_PRESERVE_ZERO_FRACTION之类的标志。

这可以通过将这些标志传递给新的JsonNormalizer::withOptions()方法来实现:

namespace My\App;

$normalizer = (new \CuyZ\Valinor\MapperBuilder())
    ->normalizer(\CuyZ\Valinor\Normalizer\Format::json())
    ->withOptions(\JSON_PRESERVE_ZERO_FRACTION);

$lowerManhattanAsJson = $normalizer->normalize(
    new \My\App\Coordinates(
        longitude: 40.7128,
        latitude: -74.0000
    )
);

// `$lowerManhattanAsJson` is a valid JSON string representing the data:
// {"longitude":40.7128,"latitude":-74.0000}

该方法接受以下JSON_*常量表示形式的 int-mask:

  • JSON_HEX_QUOT
  • JSON_HEX_TAG
  • JSON_HEX_AMP
  • JSON_HEX_APOS
  • JSON_INVALID_UTF8_IGNORE
  • JSON_INVALID_UTF8_SUBSTITUTE
  • JSON_NUMERIC_CHECK
  • JSON_PRESERVE_ZERO_FRACTION
  • JSON_UNESCAPED_LINE_TERMINATORS
  • JSON_UNESCAPED_SLASHES
  • JSON_UNESCAPED_UNICODE

JSON_THROW_ON_ERROR始终强制执行,因此不被接受。

有关更多信息,请参阅官方文档:https://www.php.net/manual/en/json.constants.php

新功能

  • 允许 JSON 规范化器设置 JSON 格式选项 ( cd5df9 )
  • 允许映射到array-key类型 ( 5020d6 )
  • 处理接口构造函数注册( 13f69a )
  • 处理来自接口的类型输入( 3af22d )
  • 引入非密封指定结构的数组语法( fa8bb0 )

错误修复

  • 仅在词法分析期间需要时处理类标记 ( c4be75 )
  • 仅在接口推断期间加载所需信息( c8e204 )

其他

  • 重命名内部类( 4c62d8 )