rutek / dataclass
用于验证类型提示类库
Requires
- php: ^7.4 || ^8.0
Requires (Dev)
- phpstan/phpstan: ^1.4
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.5
This package is not auto-updated.
Last update: 2024-09-20 13:33:40 UTC
README
Dataclass 允许您快速将普通 array
转换为类型提示的 PHP 类,自动解规范化嵌入的对象和集合,这在使用正常化程序和解正常化程序时通常需要大量工作。库灵感来自 Python pydantic 模块。它使用了从 PHP 7.4 开始可用的类型提示功能。
本包的主要目标是提供一个快速的方法来拥有严格类型提示的类,以便进一步使用,例如将请求数据包映射到严格类型的类,这样您就可以使用它代替可能或可能不满足您要求的数组。它不会替换您的数据验证,但会使您确信收到的 JSON 负载数据与后端操作期望接收的数据类型相匹配。这就像上面提到的 pydantic BaseModel
或 TypeScript 接口。
您只需要创建一个或两个类
declare(strict_types=1); class MyEmbededClass { public float $number; } class MyClass { public int $number; public ?string $optionalText = null; public MyEmbededClass $embeded; }
下一步,传递主类名和接收到的数据,例如从接收到的 JSON 到 transform
方法
$data = '{ "number": 1, "embeded": { "number": 1.23 } }'; $object = transform(MyClass::class, json_decode($data, true));
快速将接收到的数据映射到完整功能的数据类
var_dump($object)
object(MyClass) { ["number"]=> int(1) ["optionalText"]=> NULL ["embeded"]=> object(MyEmbededClass) { ["number"]=> float(1.23) } }
您无需担心从 json_decode
传递 null
,如果检测到,它将抛出 TransformException
。
您无需担心缺少字段和无效类型,因为库会检测所有类型提示要求,并抛出带有错误(准备作为响应提供)的 TransformException
,指向确切的字段和简单的错误消息,例如
echo json_encode($transformException, JSON_PRETTY_PRINT)
{ "errors": [ { "field": "optionalText", "reason": "Field must have value" }, { "field": "embeded", "reason": "Field must have value" } ] }
您还可以使用 Transform::to
方法,这实际上是 transform
辅助函数调用的。辅助函数始终使用 Transform
对象的最佳设置(一旦它们出现)。
$data = '{ "number": 1, "embeded": { "number": 1.23 } }'; $transformer = new Transform(); $object = $transformer->to(MyClass::class, json_decode($data, true));
构造函数
如果您需要使用带有类型提示参数的构造函数,您可以实现,但仅限于有限的方式。库仅支持使用负载中的值填充构造函数参数。这意味着构造函数必须使用与类属性相同的类型和变量名。例如
class MyClass { public float $number; public ?int $numberTwo = null; public function __construct(float $number) { $this->number = $number; } }
使用不同的名称或类型为构造函数参数将不会工作。目标是强制开发者填写属性。
任何包含除属性之外任何其他参数的构造函数将抛出 UnsupportedException
。参数必须与属性具有相同的类型。顺序无关紧要。如果需要,构造函数中只能存在某些属性的子集。
更多示例
请查看docs/目录以获取更多示例。
安装
非常简单
composer install rutek/dataclass
支持的类型提示
注意:请注意使用 array
类型提示。它们不能使用(如果检测到将抛出 UnsupportedException
),因为 PHP 不提供对数组项进行类型提示的方法。请参阅下面的 集合 部分以获取更多信息。
标量
支持所有 四个 PHP 标量。
可为空的字段
支持类型提示的可空性。您可以使用例如 ?string
来接受 string
和 null
。请注意,仅使用 ?string $field
并不意味着转换后的数组可能不包含此字段。它仅表示此值接受 null
。
默认值
如果您需要接受不包含某些字段的数据转换,可以使用默认值,例如:?string $field = null
。数据类库将检测到该属性在负载中不存在,并将使用默认值。
集合
PHP 不支持类型提示的 array
字段,如果您需要嵌入对象或标量的集合,必须使用 Collection
类。您需要使用具有类型提示参数解构的构造函数扩展它,例如
class Tags extends Collection { public function __construct(string ...$names) { $this->items = $names; } }
类型提示数组如 string[]
在 RFC 中被拒绝,因此这种行为可能不会很快改变。
库将检查提供的值是否与构造函数的类型提示匹配。
无法检查最小和最大项目数,但在下一个版本中可能会有这样的功能。
请注意,您还可以将 Collection 作为要转换的基础类,例如
$tags = transform(Tags::class, ['tag1', 'tag2']);
异常
TransformException
- 数据不匹配您的模式
这是您可以预期的基异常。每次您的数据(负载)传递到函数 transform(string $class, $data)
或 Transform::to
时,如果您的数据不匹配类型提示的类,您将收到 TransformException
,其中包含 getErrors(): FieldError[]
方法,该方法描述了实际发生了什么。
每个 FieldError
都包含描述哪个字段未通过类型检查的 field
以及用简单语言描述为什么它被拒绝的 reason
。如果有嵌套对象,您可以期待接收类似 parentProperty.childrenProperty
的 field
值(层级用点分隔)。
类支持 JSON 序列化,并将始终返回类似
{ "errors": [ { "field": "optionalText", "reason": "Field must have value" }, { "field": "embeded", "reason": "Field must have value" } ] }
请注意,将来可能会添加 code
字段。
UnsupportedException
- 仅当您的类型提示不受支持时
库不涵盖所有场景,因为您可以定义不会具有严格上下文的作用域的类型提示。例如,如果您使用 object
属性,将无法对其进行验证,因为任何对象都将匹配您的模式。在这种情况下,您可以期待收到 UnsupportedException
。
不受支持(尚不)
交集和并集类型
PHP 8.0 的 联合类型 和 PHP 8.1 的 交集类型 目前不受支持。
枚举
原生的 PHP 8.1 枚举 目前不受支持。
私有和受保护的属性
目前所有类型提示的字段都必须是公共的。实现此类功能是有问题的,因为您将不得不为这些属性创建获取器,这会增加不必要的开销。库旨在为从远程系统(API、队列/总线消息、浏览器)接收到的数据创建内部模式。
反射缓存
每次调用 transform
或 Transform::to
函数时,都会进行反射检查。您可以期待不久将提供缓存功能以获得更好的性能。
备注
请记住,此包的目标不是完全验证您收到的数据,而是创建简单的类,使得您的有效负载在具有复杂结构的情况下也能完全类型提示。您不需要使用带有 class
字段的 JSON 编码您的类,因为您的类型提示会告诉您的代码应该创建什么对象或数组来代替某些嵌入式值。
如果您正在创建 API 并且需要企业级的 OpenAPI 架构验证,您应该检查 hkarlstrom/openapi-validation-middleware,然后您可以使用这个库将收到的有效负载映射到类型提示的类!:)