- 后端
- 开发工具
【免费下载链接】Validation
The most awesome validation engine ever created for PHP
Validation 是 PHP 生态中著名的校验引擎,而FloatVal是其"数值与类型"分类下最常用的校验器之一:它并不要求输入在 PHP 层面上真的是float类型,而是只要能被解析成浮点数即算通过。本文将以 FloatVal 官方文档 为主体,结合 FloatVal 源码 与 单元测试,讲清它的判定规则、底层实现、与FloatType的本质区别,以及如何在项目中自定义错误模板。读完本文,你将能够准确判断"字符串数字"、科学计数法、整型等各类输入在FloatVal下的表现,并把它与其他数值类校验器正确搭配使用。
一、FloatVal 是什么:值可解析为浮点数即通过
FloatVal的定位是"值校验(Val 后缀)"而非"类型校验(Type 后缀)"。官方文档对其功能的定义只有一句话:Validate whether the input value is float——即校验输入值是否为浮点数。
它的核心语义是:不关心输入的 PHP 原生类型,只关心输入内容能否被当作一个合法的浮点数值来理解。因此:
- 真正的
float变量(如1.5、0.0、1e12)必然通过; - 内容是合法数字的字符串(如
'165.7'、'1e5')也能通过; - 甚至连整型(如
165、1、0)也会被判定为合法浮点值,因为整型可以被无损地视作浮点数。
二、基本用法:从文档示例到更多场景
官方文档给出了一组最短的用法示例,先看原始示例:
v::floatVal()->assert(1.5); // Validation passes successfully v::floatVal()->assert('1e5'); // Validation passes successfully第一个示例验证了标准的float字面量,第二个示例验证了科学计数法字符串'1e5'——这正是FloatVal区别于严格类型校验器的关键:它允许字符串形式的数值。
结合源码实现与单元测试,我们可以把行为边界扩充得更完整。根据 FloatValTest.php 的有效输入数据提供器,以下输入全部判定为合法浮点值:
v::floatVal()->validate(165); // true,整型也通过 v::floatVal()->validate(1); // true v::floatVal()->validate(0); // true v::floatVal()->validate(0.0); // true v::floatVal()->validate('1'); // true,纯数字字符串 v::floatVal()->validate('19347e12'); // true,科学计数法字符串 v::floatVal()->validate(165.0); // true v::floatVal()->validate('165.7'); // true,带小数点的字符串 v::floatVal()->validate(1e12); // true,科学计数法浮点字面量而根据同一测试文件的无效输入数据提供器,以下输入会被拒绝:
v::floatVal()->validate(''); // false,空字符串 v::floatVal()->validate(null); // false v::floatVal()->validate('a'); // false,非数字文本 v::floatVal()->validate(' '); // false,纯空白 v::floatVal()->validate('Foo'); // false此外,validate()、assert()是同一套判定逻辑的两种出口:validate()返回布尔值适合条件判断,assert()在失败时抛出异常并携带可读的错误消息。与文档中assert的用法保持一致,日常代码里两种写法都常见。
三、底层实现:filter_var 与 FILTER_VALIDATE_FLOAT
FloatVal的判定逻辑极其简洁,完整实现在 src/Validators/FloatVal.php:
public function isValid(mixed $input): bool { return is_float(filter_var($input, FILTER_VALIDATE_FLOAT)); }逐层拆解这条调用链:
filter_var($input, FILTER_VALIDATE_FLOAT)使用 PHP 内置过滤扩展尝试把输入解析为浮点数。它内部遵循 PHP 的浮点字面量语法,天然支持十进制、负号、小数点以及科学计数法(e/E指数),因此'1e5'、'19347e12'这类字符串会被解析为100000.0之类的 float 值;而''、'a'、'Foo'、null、纯空白字符串则会解析失败。is_float(...)对外层结果再做一次类型确认。这一步之所以必要,是因为FILTER_VALIDATE_FLOAT在解析成功时返回float,失败时返回false——用is_float判断可以明确区分"解析成功得到浮点数"与"解析失败返回布尔 false",避免把失败的false误判为合法值。
值得强调的是:由于filter_var会先做"值解析",所以整型输入165会被转换成165.0(float),is_float判定为真——这解释了第一节表格中165、1、0均能通过的原因。这是FloatVal作为"值校验器"的刻意设计,而非缺陷。
在类结构上,FloatVal继承自 src/Validators/Core/Simple.php 这个抽象基类。Simple把"校验"拆成两个抽象层级:子类只需实现isValid(mixed $input): bool返回布尔判定,基类则自动将其包装为evaluate(),产出统一的Result对象,供链式校验、结果过滤与异常抛出机制复用。也就是说,FloatVal只需要关心"是或不是",其余工程细节全部由框架承担。
四、与 FloatType 的区别:宽松值校验 vs 严格类型校验
这是使用FloatVal时最容易踩的坑:它和FloatType看似孪生,语义却完全不同。两者在文档的 See Also 中互相引用,建议对照阅读 FloatType 文档。
对比两个类的核心实现即可一目了然:
FloatVal(源码):is_float(filter_var($input, FILTER_VALIDATE_FLOAT))——先解析再判断,字符串数字也能通过;FloatType(源码):is_float($input)——直接检查 PHP 原生类型,只有真正的 float 变量才通过。
| 输入 | floatVal() | floatType() |
|---|---|---|
1.5 | ✅ 通过 | ✅ 通过 |
0.0 | ✅ 通过 | ✅ 通过 |
'1.5' | ✅ 通过 | ❌ 拒绝(消息:"1.5" must be a float) |
'1e5' | ✅ 通过 | ❌ 拒绝 |
165(int) | ✅ 通过 | ❌ 拒绝 |
FloatType文档中的示例也印证了这一点:
v::floatType()->assert(1.5); // Validation passes successfully v::floatType()->assert('1.5'); // → "1.5" must be a float选用建议:如果数据来自表单、API 请求等"文本输入"场景,期望用户填写数值且允许字符串形式,用FloatVal;如果数据来自强类型内部计算、必须确保变量本身是 float,用FloatType。两者配合时,一般建议"输入侧宽松、输出侧严格"。
五、与 IntVal / IntType 的对照:数值家族的行为差异
FloatVal的 See Also 还指向整型家族,这一对照有助于理解 Val/Type 后缀在整个数值校验体系中的一致性设计:
- IntVal 源码:
is_int($input)为真,或字符串匹配正则/^-?\d+$/——即整型本身或"可选负号的纯数字字符串"通过; - IntType 源码:
is_int($input)——只接受原生整型。
可见整个数值家族遵循完全一致的规律:Type 后缀校验 PHP 原生类型,Val 后缀校验"值是否可被解析为该数值"。另一个重要差异值得注意:IntVal用的是preg_match正则,因此'1.5'、'1e5'这类非整数字符串会被拒绝;而FloatVal走的是filter_var浮点过滤器,天然容忍小数与科学计数法。这也说明两个校验器的判定能力与 PHP 底层语法规则绑定,选择时不要脱离输入数据的真实形态。
六、模板机制:TEMPLATE_STANDARD 与 subject 占位符
FloatVal与其他校验器一样,通过#[Template]属性声明错误消息模板,源码中的定义如下(见 src/Validators/FloatVal.php):
#[Template( '{{subject}} must be a floating-point number', '{{subject}} must not be a floating-point number', )]对应文档中的模板表:
| Mode | Template |
|---|---|
default | {{subject}} must be a floating-point number |
inverted | {{subject}} must not be a floating-point number |
两点说明:
default与inverted:默认模式在输入不合法时使用;inverted模式用于取反场景。在Not前缀(如v::not(v::floatVal()))或反向断言时,框架会自动切换到第二条模板,保证语义仍然通顺。模板机制本身由 src/Message/Template.php 这个属性类承载,它把default、inverted文本与id(默认为Validator::TEMPLATE_STANDARD)绑定在一起。{{subject}}占位符:根据文档说明,它代表"被校验的输入值,或(若指定了)自定义校验器名称"。也就是说,如果在链式构建中给校验器起了名字,错误消息会优先展示这个名字,使报错更贴近业务上下文。关于占位符替换的完整机制,可进一步参考 docs/messages/placeholder-conversion.md。
七、分类与变更历史
- 分类(Categorization):
FloatVal同时归属Numbers与Types两个类别,这与其"按数值语义校验、又涉及类型判定"的双重属性一致。可在 docs/validators.md 的分类索引中与其他同类校验器对比检索。 - 变更历史(Changelog):
3.0.0:模板体系变更(Templates changed)——新版以#[Template]属性和TEMPLATE_STANDARD常量取代旧版消息机制,这也是所有校验器在 v3 中的统一改动;1.0.0:校验器创建(Created)。
若你正在从 v2 迁移,模板消息的改动细节可参考 docs/migrating-from-v2-to-v3.md。
八、测试验证与实战要点
FloatVal的单元测试位于 tests/unit/Validators/FloatValTest.php,它继承自框架的 RuleTestCase,通过providerForValidInput/providerForInvalidInput两套数据驱动,对上述所有"通过/拒绝"用例进行逐一断言。这套测试本身就是一份绝佳的"行为规格说明书"——当你对某个输入边界拿不准时,直接查阅该文件即可得到权威答案。
最后梳理几条实战要点:
- 接受字符串数字:
floatVal()会放过'165.7'、'1e5',适合校验表单与接口入参; - 需要严格 float 类型时:改用
floatType(),不要误用FloatVal; - 整数也会通过:
165、1、0均判定为合法浮点值,若业务上要求"必须带小数点",需另行用Regex等校验器补充约束; - 错误消息可定制:通过
setTemplate()或链式命名机制替换{{subject}} must be a floating-point number的默认文案,使其更贴合产品语境。
相关阅读
- FloatType 文档(严格类型校验)
- BoolType 文档、BoolVal 文档
- IntType 文档、IntVal 文档
- validators 总览、占位符转换机制
- 后端
- 开发工具
【免费下载链接】Validation
The most awesome validation engine ever created for PHP
相关推荐
TypeSpec Emitter 开发完全指南:从 $onEmit 到自定义代码生成
TypeSpec Emitter 开发完全指南:从 $onEmit 到自定义代码生成 本指南围绕 TypeSpec https://link.gitcode.c
后端开发工具Mongoose 数据校验(Validation)完全指南:内置校验器、自定义校验与更新校验器
Mongoose 数据校验(Validation)完全指南:内置校验器、自定义校验与更新校验器 Mongoose 作为 MongoDB 的异步对象建模库,其数据
数据库后端Gradle 工作校验(Work Validation)机制全解:静态校验与运行时校验的源码级剖析
Gradle 工作校验(Work Validation)机制全解:静态校验与运行时校验的源码级剖析 本文以 Work Validation.md 为核心骨架,结
构建工具开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考