2026/10/6 7:52:03

Respect Validation 的 EndsWith 验证器:字符串与数组的尾部匹配实现与多值支持

Respect Validation 的 EndsWith 验证器:字符串与数组的尾部匹配实现与多值支持 后端开发工具【免费下载链接】ValidationThe most awesome validation engine ever created for PHP项目地址https://gitcode.com/gh_mirrors/va/Validation点击查看免费下载导读EndsWith是 Respect Validation 库中用于校验输入是否以指定值结尾的核心验证器覆盖字符串与数组两种输入类型。本文以其官方文档 docs/validators/EndsWith.md 为骨架结合 src/Validators/EndsWith.php 的源码实现与 tests/unit/Validators/EndsWithTest.php、tests/feature/Validators/EndsWithTest.php 的测试用例完整讲解其构造函数签名、字符串/数组匹配语义、多值匹配、消息模板占位符以及链式 API 变体。读完本文你将能准确使用v::endsWith()完成后缀校验并理解其内部类型守卫与多字节安全实现原理。功能定位与Contains同族但只校验结尾EndsWith在验证器家族中与Contains属于同一类包含性匹配工具。官方文档明确说明该验证器与Contains()类似但只校验其中一个值是否出现在输入的最末尾。二者在 docs/validators/Contains.md 与 docs/validators/EndsWith.md 中互为 See Also且同样归类于 Arrays数组与 Strings字符串两大类别。一个直观的区分Contains校验字符串中是否包含某值EndsWith则进一步限定该值必须落在字符串的尾部或数组的最后一个元素。例如输入lorem ipsum中既包含也以ipsum结尾两者都能通过但输入ipsum lorem只包含ipsum而不以其结尾Contains通过而EndsWith失败。构造函数签名与基本用法构造函数支持两种形态对应文档首部的 API 说明EndsWith(mixed $endValue) EndsWith(mixed $endValue, mixed ...$endValues)单值形态只校验一个结尾值多值形态自 3.1.0 起通过可变参数...$endValues传入多个候选值任一匹配即通过or 语义。在源码中两种形态统一收敛为public function __construct(mixed $endValue, mixed ...$endValues) { $this-endValues [$endValue, ...$endValues]; }可见 src/Validators/EndsWith.php 将第一个参数与后续可变参数合并为内部数组$endValues并保证其非空var non-empty-arraymixed。字符串用法示例官方文档给出的基础示例v::endsWith(ipsum)-assert(lorem ipsum); // Validation passes successfully v::endsWith(, PhD, , doctor)-assert(Jane Doe, PhD); // Validation passes successfully第二个示例展示了多值形态只要Jane Doe, PhD以, PhD或, doctor中任意一个结尾即通过这里命中前者。注意多值形态下即使传入, doctor这样的干扰项也不会导致失败。数组用法示例v::endsWith(ipsum)-assert([lorem, ipsum]); // Validation passes successfully v::endsWith(., ;)-assert([this, is, a, tokenized, phrase, .]); // Validation passes successfully v::endsWith(., ;)-assert([this, is, a, tokenized, phrase]); // → [this, is, a, tokenized, phrase] must end with . or ;对数组而言EndsWith只关心最后一个元素即end($input)中间的任意元素一概忽略。第三个示例中数组末尾元素是phrase既不是.也不是;因此抛出校验异常错误消息含{{endValues|list:or}}列表渲染随之生成。源码级匹配语义剖析evaluate()是验证器的核心入口负责选择模板并生成 Resultpublic function evaluate(mixed $input): Result { $template self::TEMPLATE_STANDARD; $parameters [ endValue $this-endValues[0], endValues $this-endValues, ]; if (count($this-endValues) 1) { $template self::TEMPLATE_MULTIPLE_VALUES; } return Result::of($this-validateIdentical($input), $input, $this, $parameters, $template); }模板的选择逻辑很清晰只有一个候选值时用TEMPLATE_STANDARD消息只含{{endValue}}有多个候选值时自动切换为TEMPLATE_MULTIPLE_VALUES消息用{{endValues|list:or}}渲染成 A or B 列表。实际的匹配逻辑位于私有方法validateIdentical()其行为可归纳为三条规则规则一数组输入只看末元素且用严格比较。if (is_array($input) end($input) $endValue) { return true; }end($input) $endValue是严格全等比较不进行类型强制转换。这一点被单元测试精准锁定[new EndsWith(1), [2, 3, 1]]判定为有效整数1与末元素1全等[new EndsWith(1), [2, 3, 1]]判定为无效字符串1与整数1不全等[new EndsWith(1), [2, 3, 1]]判定为有效字符串1与字符串1全等。规则二字符串输入使用多字节安全的位置判断。if ( is_string($input) is_string($endValue) mb_strrpos($input, $endValue) mb_strlen($input) - mb_strlen($endValue) ) { return true; }实现技巧值得注意它并非先查末尾子串再比对而是借助mb_strrpos多字节安全的最后一次出现位置与长度差做数学判断——当$endValue最后一次出现在$input中的位置恰等于strlen($input) - strlen($endValue)时$endValue必然是$input的后缀。所有mb_*函数确保了对 UTF-8 等多字节字符集的安全处理避免按字节切割导致乱码误判。规则三任一候选值命中即返回trueor 语义。外层foreach ($this-endValues as $endValue)遍历全部候选值只要有一个命中就提前返回否则全部遍历完返回false。大小写敏感3.0.0 起的行为变更Changelog 中 3.0.0 一栏写明 Case-insensitive comparison removed移除了大小写不敏感比较。也就是说当前版本下EndsWith是严格大小写敏感的。单元测试用反例锁定该行为[new EndsWith(foo), barbazFOO], // FOO 大写无效 [new EndsWith(foo), barfaabaz], // 位置不对无效 [new EndsWith(foo), faabarbaz], // 结尾不符无效如果需要大小写不敏感的结尾匹配不应指望EndsWith本身而应组合其他手段例如配合Regex使用i修饰符见 docs/validators/Regex.md或使用Lowercase先归一化输入。这一点是迁移自 v2 用户需要特别留意的破坏性变更。内部类型守卫非字符串输入安全失败文档强调Only string inputs and string end values are checked; non‑string values are considered invalid but will not produce PHP errors thanks to internal type guards.这正是validateIdentical()中两个is_string()守卫的作用。以mb_strrpos为例若直接对非字符串输入调用会导致 PHP 警告甚至 TypeError而源码通过类型检查将非字符串路径静默导向false校验失败从而把崩溃转化为可预期的校验失败。feature 测试显式覆盖了这一边界场景// ensure non-string values do not throw errors and are considered invalid test(non-string input or end value are invalid, function (): void { expect(fn() v::endsWith(foo)-assert(123)) -toThrow(ValidationException::class); expect(fn() v::endsWith(123)-assert(foo)) -toThrow(ValidationException::class); });assert(123)会抛出 ValidationException校验失败但不会产生 mb_strrpos(): Argument #1 ($haystack) must be of type string 一类的 PHP 警告或 TypeError。单元测试同样收录了这两个反例[new EndsWith(foo), 123]与[new EndsWith(123), foo]注释明确写着 non-string inputs/values should not trigger warnings。消息模板与占位符EndsWith通过 PHP 8 属性#[Template]声明两套消息模板对应两种模式官方文档完整罗列如下。EndsWith::TEMPLATE_STANDARD单值ModeTemplatedefault{{subject}} must end with {{endValue}}inverted{{subject}} must not end with {{endValue}}EndsWith::TEMPLATE_MULTIPLE_VALUES多值ModeTemplatedefault{{subject}} must end with {{endValues|list:or}}inverted{{subject}} must not end with {{endValues|list:or}}占位符说明PlaceholderDescriptionsubjectThe validated input or the custom validator name (if specified).endValueThe value that will be checked to be at the end of the input.endValuesAdditional values to check.{{endValues|list:or}}中的list:or是模板渲染器见 src/Message/ 下的 Formatter 与 InterpolationRenderer 体系提供的列表过滤器将endValues数组渲染为以 or 连接的英文列表。feature 测试的断言直接印证了该渲染结果test(Scenario #5, catchMessage( fn() v::endsWith(Mr., Dr.)-assert(John Doe), fn(string $message) expect($message)-toBe(John Doe must end with Mr. or Dr.), )); test(Scenario #6, catchFullMessage( fn() v::not(v::endsWith(divorced., PhD.))-assert(John Doe, PhD.), fn(string $fullMessage) expect($fullMessage)-toBe(- John Doe, PhD. must not end with divorced. or PhD.), ));多值 default 消息John Doe must end with Mr. or Dr.多值 inverted 消息John Doe, PhD. must not end with divorced. or PhD.。另外消息中的subject被渲染为带引号的输入值如bar或 PHP 数组字面量如[bar, foo]这在catchMessage与catchFullMessage的多个场景Scenario #1#4中均有覆盖// Scenario #1 v::endsWith(foo)-assert(bar); // → bar must end with foo // Scenario #2 v::not(v::endsWith(foo))-assert([bar, foo]); // → [bar, foo] must not end with foo模板本身定义在 src/Validators/EndsWith.php 顶部的属性中#[Template( {{subject}} must end with {{endValue}}, {{subject}} must not end with {{endValue}}, )] #[Template( {{subject}} must end with {{endValues|list:or}}, {{subject}} must not end with {{endValues|list:or}}, self::TEMPLATE_MULTIPLE_VALUES, )]若需自定义消息可通过库的setTemplate()/withTemplate()机制替换详见 docs/validators/Templated.md 与 docs/messages/placeholder-conversion.md。链式 API 与组合变体EndsWith被接入库的 Mixins 体系见 src/Mixins/)提供了丰富的链式入口全部签名统一为endsWith(mixed $endValue, mixed ...$endValues)变体定义位置作用v::endsWith(...)src/Mixins/Builder.php静态入口返回 Chain-endsWith(...)src/Mixins/Chain.php链式追加v::notEndsWith(...)/-notEndsWith(...)src/Mixins/NotBuilder.php、src/Mixins/NotChain.php取反校验v::nullOrEndsWith(...)/-nullOrEndsWith(...)src/Mixins/NullOrBuilder.php、src/Mixins/NullOrChain.phpnull 视为通过v::allEndsWith(...)/-allEndsWith(...)src/Mixins/AllBuilder.php、src/Mixins/AllChain.php对数组每个元素应用v::keyEndsWith($key, ...)/-keyEndsWith($key, ...)src/Mixins/KeyBuilder.php、src/Mixins/KeyChain.php校验数组指定键v::propertyEndsWith($prop, ...)/-propertyEndsWith($prop, ...)src/Mixins/PropertyBuilder.php、src/Mixins/PropertyChain.php校验对象指定属性v::undefOrEndsWith(...)/-undefOrEndsWith(...)src/Mixins/UndefOrBuilder.php、src/Mixins/UndefOrChain.php未定义视为通过例如同时校验以.md结尾与不以.bak结尾可以链式组合v::endsWith(.md) -not(v::endsWith(.bak)) -assert(docs/validators/EndsWith.md);feature 测试中的v::not(v::endsWith(foo))-assert([bar, foo])就是取反变体的直接证据数组以foo结尾取反后校验失败。与其他验证器的关系与选型官方文档 See Also 列出五个相关验证器它们构成一组首尾/包含性匹配工具集Contains校验输入包含某值字符串任意位置 / 数组任意元素是EndsWith的宽松版StartsWith校验输入以某值开头与EndsWith首尾对称。其源码 src/Validators/StartsWith.php 与EndsWith结构几乎镜像——数组用reset($input) $startValue检查首元素字符串用mb_strpos($input, $startValue) 0判断前缀同样支持多值...$startValues与TEMPLATE_MULTIPLE_VALUESIn校验输入是否落在给定的值集合内Regex正则表达式匹配适合实现大小写不敏感或更复杂的后缀模式Trimmed校验字符串无首尾空白常与EndsWith配合避免尾部空格导致误判。选型建议需要严格后缀无论字符串还是数组末元素且大小写敏感时用EndsWith只需包含语义时用Contains需要正则级别的后缀模式如/\.(md|txt)$/i时用Regex。变更历史官方 Changelog 记录了该验证器的演进轨迹VersionDescription3.1.0Added support for multiple values3.0.0Case-insensitive comparison removed0.3.9Created0.3.9EndsWith随早期版本创建3.0.0移除大小写不敏感比较此后为严格大小写敏感破坏性变更v2 迁移用户需注意3.1.0新增多值支持即EndsWith($endValue, ...$endValues)与TEMPLATE_MULTIPLE_VALUES、{{endValues|list:or}}列表消息渲染。实战小结EndsWith是 Respect Validation 中语义清晰、实现稳健的尾部匹配验证器。使用要点可归结为四点字符串多字节安全的后缀判断大小写敏感数组严格全等比较最后一个元素类型不自动转换多值...$endValues提供 or 语义任一命中即通过消息自动渲染为A or B列表类型守卫非字符串输入或非字符串结束值一律判定为校验失败但绝不触发 PHP 类型相关警告可放心用于表单等不可信输入场景。配合not、nullOr、all、key、property等 Mixins 变体EndsWith可以在链式校验中覆盖对象属性、数组键以及批量元素等复杂场景是文件后缀、句子收尾、序列末元素等校验需求的直接答案。赞分享后端开发工具【免费下载链接】ValidationThe most awesome validation engine ever created for PHP项目地址https://gitcode.com/gh_mirrors/va/Validation点击查看免费下载相关推荐深入解析 Respect Validation 的 ContainsAny 验证器数组与字符串的“任一包含”校验深入解析 Respect Validation 的 ContainsAny 验证器数组与字符串的“任一包含”校验 导读 ContainsAny 是 Respe后端开发工具Kornia Filtering API 深度指南用 filter2d / filter2d_separable / filter3d 自定义图像滤波算子Kornia Filtering API 深度指南用 filter2d / filter2d_separable / filter3d 自定义图像滤波算子 本后端开发工具TypeScript 类型挑战 EndsWith 全解用模板字符串类型与 infer 实现字符串结尾匹配TypeScript 类型挑战 EndsWith 全解用模板字符串类型与 infer 实现字符串结尾匹配 导读 本文围绕 type challenges 中等示例工程上一篇CAJ转PDF一条命令本地搞定开源工具caj2pdf实战指南下一篇Mac Mouse Fix使用指南让普通鼠标在macOS上脱胎换骨的免费神器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考