ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Respect Validation 的 Instance 验证器:基于 instanceof 的对象与接口类型校验实战指南

Respect Validation 的 Instance 验证器:基于 instanceof 的对象与接口类型校验实战指南 后端开发工具【免费下载链接】ValidationThe most awesome validation engine ever created for PHP项目地址https://gitcode.com/gh_mirrors/va/Validation点击查看免费下载导读Instance是 Respect ValidationPHP 领域广受欢迎的校验引擎对应源码位于 src/Validators/Instance.php中用于对象类型归属校验的核心验证器。它基于 PHP 原生instanceof语义既能校验某个对象是否是指定类的实例也能校验其是否实现了某个接口可广泛用于依赖注入容器、领域模型校验、DTO 属性约束等场景。读完本文你将掌握Instance的完整 API 用法、消息模板定制、作为 PHP 属性Attribute使用的方式以及它与其他对象类验证器的边界与配合策略。验证器概述签名Instance(class-string $class)功能校验输入值是否为给定类class或接口interface的实例。分类Objects对象类验证器。版本历史自 0.3.9 版本起加入。它是最简单的对象类型断言型验证器传入一个class-string类名字符串然后用 PHP 的instanceof操作符对输入做判断。由于instanceof同时支持类和接口因此它天然覆盖是某个具体类的对象与实现了某个接口的对象两类需求。基本用法与代码示例在文档 docs/validators/Instance.md 中给出的最小可用示例v::instance(DateTime)-assert(new DateTime); // Validation passes successfully v::instance(Traversable)-assert(new ArrayObject); // Validation passes successfully第一个示例校验对象是DateTime的实例第二个示例利用Traversable这一接口ArrayObject实现了它因此同样通过校验。这说明Instance的判断对象既可以是具体类也可以是接口名。单元测试 tests/unit/Validators/InstanceTest.php 中对合法输入的定义与此完全一致new Instance(DateTime::class)new DateTime()new Instance(Traversable::class)new ArrayObject()new Instance(ArrayIterator::class)new ArrayIterator()同一测试文件中的非法输入则展示了失败边界空字符串、null以及类型不匹配的对象SplFileInfo类声明配stdClass实例都会被拒绝。特别值得注意null永远不会通过instanceof判断因此Instance不接收null如需允许空值请参考下文与NullOr的组合方式。源码实现原理Instance的整个实现非常精简src/Validators/Instance.php#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] #[Template( {{subject}} must be an instance of {{class|quote}}, {{subject}} must not be an instance of {{class|quote}}, )] final readonly class Instance implements Validator { /** param class-string $class */ public function __construct( private string $class, ) { } public function evaluate(mixed $input): Result { return Result::of($input instanceof $this-class, $input, $this, [class $this-class]); } }从源码结构可以提取以下关键事实校验逻辑即一行instanceofevaluate()内执行$input instanceof $this-class结果通过Result::of(...)包装返回同时将class作为消息参数传入。所有验证器共用的evaluate(mixed $input): Result契约定义在 src/Validator.php 的Validator接口中。final readonly class验证器为只读不可变设计构造参数$class一经注入不可修改保证校验规则稳定。可作 PHP 属性使用#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]表明它可挂在类属性上且允许重复声明——这意味着你可以给一个属性同时标注多个Instance约束配合AnyOf即可表达属于 A 或 B的联合类型语义。消息模板随类定义#[Template(...)]声明了默认与反向两种消息模板分别对应校验失败与取反v::not(v::instance(...))场景。反向校验与组合用法取反must not be an instance of借助Not包装器可反转语义这在黑名单类型场景例如拒绝接收某种内部类型中很有用v::not(v::instance(Traversable))-assert(new ArrayObject); // → ArrayObject { getArrayCopy() [] } must not be an instance of Traversable允许 null与NullOr组合由于null无法通过instanceof当字段允许为空对象时应将Instance包进 NullOrv::nullOr(v::instance(DateTime::class))-assert(null); // 通过 v::nullOr(v::instance(DateTime::class))-assert(new DateTime); // 通过在属性校验中表达联合类型结合 AnyOf 与 Property可表达必须是 A 或 B 的实例这类更复杂的类型约束语义上等价于联合类型union type的运行时校验。消息模板与占位符模板定义文档中给出了Instance::TEMPLATE_STANDARD的两种模式TEMPLATE_STANDARD常量在Validator接口中定义为__standard__模式模板内容default默认{{subject}} must be an instance of {{class|quote}}inverted取反{{subject}} must not be an instance of {{class|quote}}占位符说明占位符说明class构造时传入的类名或接口名class-stringsubject被校验的输入值若指定了自定义验证器名称见 Named则为该名称文档描述中提到消息模板包含{{instanceName}}但结合源码实际使用的{{class|quote}}占位符[class $this-class]可以确认当前实现中的模板占位符是class请以源码为准。管道修饰符placeholder pipes模板中的{{class|quote}}使用了管道修饰符quote——在 docs/messages/placeholder-pipes.md 中说明占位符后跟|修饰符可自定义值的渲染方式。quote修饰符会把类名用反引号包裹这也是最终消息中类名带的原因v::instance(DateTime::class)-assert(); // → must be an instance of DateTime你也可以在assert()或 Templated 中自定义消息模板并引用占位符例如v::instance(DateTime::class)-assert($input, {{subject}} 必须是 {{class|quote}} 的实例);属性Attribute场景对象属性上的类型约束Instance支持Attribute::TARGET_PROPERTY因此可配合 Attributes 验证器直接在类属性上声明类型约束。参考 Attributes.md 中对象属性注解的写法你可以这样约束一个 DTO 字段use Respect\Validation\Validators as Validator; final class Payment { public function __construct( #[Validator\Instance(DateTimeInterface::class)] public mixed $paidAt, ) { } } v::attributes()-assert(new Payment(new DateTimeImmutable())); // Validation passes successfully需要说明的是Attributes 在递归校验联合类型union type属性时会先用Instance检查对象是否属于嵌套类型再决定是否继续递归这体现了Instance在框架内部类型分派中承担的基础判断职责。验证失败消息的实际形态功能测试 tests/feature/Validators/InstanceTest.php 给出了四种典型场景的完整输出可用于核对你的消息格式化结果场景调用消息输出默认模式标量输入v::instance(DateTime::class)-assert() must be an instance of \DateTime取反模式v::not(v::instance(Traversable::class))-assert(new ArrayObject())ArrayObject { getArrayCopy() [] } must not be an instance of Traversable完整消息链式v::instance(ArrayIterator::class)-assert(new stdClass())- \stdClass {} must be an instance of ArrayIterator完整消息 取反v::not(v::instance(stdClass::class))-assert(new stdClass())- \stdClass {} must not be an instance of stdClass可以看到消息中subject会经由项目的 Stringifier 机制渲染为可读字符串如stdClass {}、ArrayObject { getArrayCopy() [] }关于占位符转换与自定义渲染修饰符的细节可参考 docs/messages/placeholder-conversion.md。与相关对象类验证器的选型边界文档末尾的 See Also 给出了四个高度相关的验证器选型时可按职责区分Countable校验对象是否实现Countable接口属于行为能力判断而非类型归属IterableType校验输入是否为 iterable类型含数组与Traversable对象IterableVal与IterableType相对偏向值语义侧的 iterable 判断ObjectType只关心是否为对象不关心具体类或接口Instance最精确的一档锁定具体类或接口的归属关系。实践中可按是否为对象 → 是否为实现某接口 → 是否为某具体类/接口实例的粒度逐层选择宽泛判断用ObjectType能力判断用Countable/IterableType精确约束用Instance。小结Instance是 Respect Validation 中语义最简单、边界最清晰的对象类验证器一行instanceof判断 可定制消息模板 属性注解能力使其在 DTO 校验、依赖类型约束、联合类型运行时分派等场景中都是首选工具。建议在实际项目中结合NullOr允许空值、Not取反与Templated/Named定制消息共同使用并可通过 Attributes 将类型约束直接声明在类属性上实现声明式、可读性强的对象校验模型。赞分享后端开发工具【免费下载链接】ValidationThe most awesome validation engine ever created for PHP项目地址https://gitcode.com/gh_mirrors/va/Validation点击查看免费下载相关推荐深入理解 TypeScript 对象类型接口、类型别名与形状校验实战基于 The Concise TypeScript Book深入理解 TypeScript 对象类型接口、类型别名与形状校验实战基于 The Concise TypeScript Book 在 TypeScript文档教程OpenTofu 插件协议Plugin Protocol完全指南gRPC 线协议、版本策略与 SDK 开发实践OpenTofu 插件协议Plugin Protocol完全指南gRPC 线协议、版本策略与 SDK 开发实践 OpenTofu Core 与 Provi后端开发工具TypeGraphQL 参数与输入校验Validation实战指南基于 class-validator 的自动校验与自定义校验器TypeGraphQL 参数与输入校验Validation实战指南基于 class validator 的自动校验与自定义校验器 TypeGraphQL后端GraphQLAPI设计上一篇NVIDIA Profile Inspector 深度解析解锁显卡隐藏性能的终极指南下一篇dotnet/skills 插件架构深度解析plugin.json 与 version.json 如何协同多端分发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表