入门指南¶
安装¶
示例¶
某个应用需要处理来自外部 API 的数据。响应采用 JSON 格式,描述一个讨论主题及其回复。这些输入是否有效尚不确定,而且直接操作原始 JSON 字符串既费力又低效。
{
"id": 1337,
"content": "Do you like potatoes?",
"date": "1957-07-23 13:37:42",
"answers": [
{
"user": "Ella F.",
"message": "I like potatoes",
"date": "1957-07-31 15:28:12"
},
{
"user": "Louis A.",
"message": "And I like tomatoes",
"date": "1957-08-13 09:05:24"
}
]
}
应用必须确保自己能正确处理这些数据。将输入封装在值对象中有助于做到这一点。
必须使用类来描述所需的数据结构。
final readonly class Thread
{
public function __construct(
public int $id,
public string $content,
public DateTimeInterface $date,
/** @var Answer[] */
public array $answers,
) {}
}
final readonly class Answer
{
public function __construct(
public string $user,
public string $message,
public DateTimeInterface $date,
) {}
}
然后使用映射器将源数据填充到这些对象中。
public function getThread(int $id): Thread
{
$rawJson = $this->client->request("https://example.com/thread/$id");
try {
return (new \CuyZ\Valinor\MapperBuilder())
->mapper()
->map(
Thread::class,
new \CuyZ\Valinor\Mapper\Source\JsonSource($rawJson)
);
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
// Do something…
}
}
映射高级类型¶
尽管建议将输入映射到值对象,但在某些情况下映射到其他类型可能更容易/更灵活。
例如,可以映射到对象数组:
try {
$objects = (new \CuyZ\Valinor\MapperBuilder())
->mapper()
->map(
'array<' . SomeClass::class . '>',
[/* … */]
);
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
// Do something…
}
对于简单的用例,可以使用数组形状: