- 后端
- 开发工具
【免费下载链接】Validation
The most awesome validation engine ever created for PHP
本篇技术指南以 Respect/Validation 仓库中的 Uuid 校验器文档 为骨架,系统讲解v::uuid()的构造签名、版本限定(v1~v8)、模板消息定制,并结合 src/Validators/Uuid.php 源码与 单元测试、特性测试 深入剖析其底层实现。读完本文,你将掌握如何在 PHP 8.5+ 项目中正确使用、定制并理解 UUID 校验规则,包括如何应对ramsey/uuid依赖缺失、非法版本参数以及非字符串输入等边界场景。
一、规则概述与构造签名
Uuid校验器用于判断输入是否为合法的 UUID(Universally Unique Identifier),并且可选地限定其版本为 1 至 8。该规则在 validators.md 中被归类为Strings(字符串)类别。
文档中给出的三种构造签名如下:
Uuid()Uuid(int $version)Uuid(int $version, UuidFactory $uuidFactory)
对应源码 src/Validators/Uuid.php 的构造函数:
public function __construct( private readonly int|null $version = null, UuidFactory|null $uuidFactory = null, )$version:期望校验的 UUID 版本,null表示不限定版本(只要解析出是 UUID 即通过);$uuidFactory:解析器工厂,默认使用new UuidFactory()。
1.1 依赖说明:ramsey/uuid
该规则基于ramsey/uuid库实现。在 composer.json 中:
ramsey/uuid: ^4位于require-dev中;- 在
suggest中注明"ramsey/uuid": "Enables the UUID rule if available"。
也就是说,运行官方测试套件需要安装该依赖;生产环境使用Uuid规则时,你需要自行执行composer require ramsey/uuid。源码构造函数中做了显式防护(src/Validators/Uuid.php):
if ($uuidFactory === null && !class_exists(UuidFactory::class)) { throw new MissingComposerDependencyException( 'Uuid rule requires ramsey/uuid package', 'ramsey/uuid', ); }如果未安装依赖就实例化规则,会抛出MissingComposerDependencyException,并提示所需的包名ramsey/uuid。
1.2 版本参数校验
若显式传入$version,构造函数会先调用isSupportedVersion()校验范围(src/Validators/Uuid.php):
private function isSupportedVersion(int $version): bool { return $version >= 1 && $version <= 8; }版本不在 1~8 之间时抛出InvalidValidatorException,消息为Only versions 1 to 8 are supported: %d given。这一点被 单元测试 明确覆盖:
self::expectException(InvalidValidatorException::class); self::expectExceptionMessage('Only versions 1 to 8 are supported: ' . $version . ' given'); new Uuid($version);二、基本用法与代码示例
文档中给出了最核心的实操示例,此处完整保留并补充说明:
// 不限定版本:任何合法 UUID(v1~v8)均通过 v::uuid()->assert('eb3115e5-bd16-4939-ab12-2b95745a30f3'); // Validation passes successfully // 非 UUID 字符串 → 校验失败 v::uuid()->assert('Hello World!'); // → "Hello World!" must be a UUID // 不带连字符的紧凑格式同样合法 v::uuid()->assert('eb3115e5bd164939ab122b95745a30f3'); // Validation passes successfully // 限定 v1 v::uuid(1)->assert('eb3115e5-bd16-4939-ab12-2b95745a30f3'); // → "eb3115e5-bd16-4939-ab12-2b95745a30f3" must be a UUID v1 // 限定 v4 v::uuid(4)->assert('eb3115e5-bd16-4939-ab12-2b95745a30f3'); // Validation passes successfully // 限定 v8 v::uuid(8)->assert('00112233-4455-8677-8899-aabbccddeeff'); // Validation passes successfully // 接受 Ramsey\Uuid\UuidInterface 对象作为输入 v::uuid(4)->assert(\Ramsey\Uuid\Uuid::fromString('eb3115e5-bd16-4939-ab12-2b95745a30f3')); // Validation passes successfully2.1 支持的输入类型
从源码 src/Validators/Uuid.php 可以看到,规则接受两类输入:
if (!is_string($input) && !($input instanceof UuidInterface)) { return Result::failed($input, $this, $parameters, $template); }- 字符串:标准 8-4-4-4-12 带连字符格式,或去掉连字符的紧凑格式(32 位十六进制);
Ramsey\Uuid\UuidInterface对象:即\Ramsey\Uuid\Uuid::fromString()等工厂方法产出的对象。
其余类型(数组、布尔值、普通对象、空字符串等)会直接判定失败。这一行为由 单元测试 中的providerForInvalidInput验证,包括''、[]、true、false、new stdClass()等场景。
2.2 非法 UUID 的判定
值得注意的是,nil UUID(全零)00000000-0000-0000-0000-000000000000也被视为非法。测试数据中还包含一个典型反例g71a18f4-3a13-11e7-a919-92ebcb67fe33(包含g这一非十六进制字符),说明解析失败即校验失败。
三、源码级原理:evaluate() 的执行流程
Uuid实现了Validator接口,核心逻辑在evaluate()方法中(src/Validators/Uuid.php),整体流程如下:
- 选择模板:若指定了版本,使用
TEMPLATE_VERSION(__version__),否则使用TEMPLATE_STANDARD,并携带['version' => $this->version]参数; - 类型检查:非字符串且非
UuidInterface实例直接返回失败结果; - 解析:字符串交给
$this->uuidFactory->fromString($input)解析,对象则直接使用;解析抛出的任何Throwable都被捕获并转为失败结果; - 提取版本:通过
$uuid->getFields()->getVersion()取得 UUID 的版本号(v1~v8); - 判定:
- 指定版本时:
$uuidVersion === $this->version; - 未指定版本时:
$uuidVersion !== null(即只要是合法 UUID 就通过)。
- 指定版本时:
这里体现了"无版本参数 = 任意版本皆可"的设计:未指定版本时,只要getVersion()有值即通过。单元测试用ALL_VERSIONS常量覆盖了 v1~v8 全部样例字符串、紧凑格式字符串与RamseyUuid::fromString()对象三种输入形态(tests/unit/Validators/UuidTest.php),并交叉验证了"期望版本与输入版本不一致时失败"的全部组合。
此外,ContainerRegistry.php 中已将UuidFactory::class注册进默认容器(UuidFactory::class => new Instantiator(UuidFactory::class)),因此在默认装配下,规则会自动获得解析工厂,无需手工注入。
四、错误消息模板与占位符
规则通过 PHP 8 属性(#[Template])声明消息模板,可同时作为属性(Attribute)用于属性级校验:类声明为#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]。
4.1Uuid::TEMPLATE_STANDARD
| 模式 | 模板 |
|---|---|
default | {{subject}} must be a UUID |
inverted | {{subject}} must not be a UUID |
4.2Uuid::TEMPLATE_VERSION
| 模式 | 模板 |
|---|---|
default | {{subject}} must be a UUID v{{version\|raw}} |
inverted | {{subject}} must not be a UUID v{{version\|raw}} |
4.3 占位符说明
| 占位符 | 说明 |
|---|---|
subject | 被校验的输入值,或自定义的校验器名称(若指定) |
version | 期望的 UUID 版本号 |
模板中的{{version|raw}}使用了占位符管道修饰符(Placeholder Pipe),raw修饰符可去掉默认的引号包裹(详见 placeholder-pipes.md),从而在错误消息中呈现v1、v4这类不带引号的版本号。
4.4 消息渲染示例
特性测试 精确断言了消息内容,例如:
v::uuid()->assert('g71a18f4-3a13-11e7-a919-92ebcb67fe33'); // → "g71a18f4-3a13-11e7-a919-92ebcb67fe33" must be a UUID v::uuid(1)->assert('e0b5ffb9-9caf-2a34-9673-8fc91db78be6'); // → "e0b5ffb9-9caf-2a34-9673-8fc91db78be6" must be a UUID v1 v::not(v::uuid())->assert('fb3a7909-8034-59f5-8f38-21adbc168db7'); // → "fb3a7909-8034-59f5-8f38-21adbc168db7" must not be a UUIDinverted模板由v::not()包装时自动启用;assert()抛出的异常消息可直接用于面向用户或日志的错误展示。
五、组合用法与进阶场景
Uuid规则可无缝嵌入 Respect/Validation 的链式与批量 API:
- 取反:
v::not(v::uuid())校验"不是合法 UUID"; - 数组批量校验:
v::allUuid()、v::allUuid($version)(见 src/Mixins/AllBuilder.php),逐项校验数组中的每个元素; - 键值校验:
v::keyUuid('user_id', 4)(见 src/Mixins/KeyBuilder.php),对关联数组指定键做 v4 UUID 校验; - 属性级校验:借助
#[Attribute]特性,可直接把规则注解到 DTO 属性上。
版本限定在实际业务中的典型价值在于:例如"用户 ID 必须为 v4 随机 UUID"或"订单号必须为 v7 时间序 UUID",通过v::uuid(4)/v::uuid(7)即可把格式与语义一并约束。
六、变更历史与相关规则
文档 Changelog 记载了该规则的演进:
| 版本 | 说明 |
|---|---|
| 3.0.0 | 消息模板调整(Templates changed) |
| 3.0.0 | 开始依赖ramsey/uuid |
| 2.0.0 | 规则创建 |
在 v3 中规则重构为基于Result对象的evaluate()结构,且模板机制与占位符管道全面升级。同属字符串校验的相关规则可参照 Base、Decimal 与 Digit:例如v::base(16)校验十六进制数字串、v::digit()校验纯数字,与v::uuid()一样都属于格式类字符串规则,可根据业务粒度组合选用。
七、总结
Uuid校验器是一个"小而精"的规则:通过可选的版本参数覆盖 v1~v8 全谱系校验,接受字符串与UuidInterface对象两种输入,兼容带连字符与紧凑格式,并以MissingComposerDependencyException/InvalidValidatorException两类异常对依赖缺失和非法参数做出明确反馈。无论是日常表单校验、API 参数过滤,还是 DTO 属性注解校验,v::uuid()都提供了开箱即用且可定制错误消息的解决方案。
- 后端
- 开发工具
【免费下载链接】Validation
The most awesome validation engine ever created for PHP
相关推荐
Respect Validation 长度校验器 Length 深入解析:从基础用法到源码原理
Respect Validation 长度校验器 Length 深入解析:从基础用法到源码原理 本指南围绕 PHP 验证库 Respect Validation
后端开发工具Respect\Validation 邮箱校验器(Email Validator)完全指南:从基础用法到源码级原理
Respect\Validation 邮箱校验器(Email Validator)完全指南:从基础用法到源码级原理 本指南以 Respect\Validatio
后端开发工具Respect Validation 中的 GreaterThanOrEqual 校验器:从 API 用法到比较运算的源码级剖析
Respect Validation 中的 GreaterThanOrEqual 校验器:从 API 用法到比较运算的源码级剖析 Respect Validat
后端开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考