adeptoas / sniff-array
用于检查数组规格一致性的工具
Requires
- php: >=7.0.0
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^4.0
- squizlabs/php_codesniffer: ^2.5
README
这是一个轻量级的库,用于检查给定的数组是否符合特定规格
安装
将此添加到 composer.json
"require": { "adeptoas/sniff-array": "^1.0.0" }
请确保合并您的 require-blocks!
使用方法
ArraySniffer
__construct(array $spec, bool $throw = false)
使用给定的 spec 初始化 ArraySniffer。错误处理可以通过 throw 指定,否则每个嗅探将简单地返回 false。
sniff(array $array): bool
开始检查 array 是否符合当前 ArraySniffer 实例的规格。
static arrayConformsTo(array $spec, array $data, bool $throw = false): bool
检查 array 是否符合 spec。这与在 ArraySniffer 实例上调用 sniff 相同,但主要用于一次性检查
SplSniffer
此库为 PHP 中的原始/SPL 类型提供了一些嗅探器。它们主要用于内部验证目的,但您也可以使用它们作为独立的验证嗅探器。
static forType(string $type): SplSniffer
返回一个适合检查符合 type 的 SplSniffer 子类。
sniff(mixed $val, bool $isStrict = false): bool
检查 val 是否符合当前 SplSniffer 实例类型所隐含的规格。isStrict 指定是否应将某些边缘情况视为有效(请参阅下面的进一步说明)
规格
基本类型
此库提供的基本类型识别包括
- 字符串
- 整数
- 数字
- 布尔值
- 混合
- 数组
- 对象
一些常见别名也已实现
- 布尔值 => 布尔
- 整数 => 整数
- 数字 => 数字
- 任何 => 混合
- 空 => 空值
- 类 => 对象
严格的规格通过类型后跟感叹号 ! 来表示,并缩小可接受值的范围。特别是
- 字符串!不接受空字符串
'' - int!不接受
0 - 数字!不接受
0或NAN - array!不接受空数组
[] - object!不接受字段为0的 stdClass 对象
new stdClass() - mixed!不接受任意数组,只接受纯原始数据
作为原始规格的 array 简单表示任何形式的任意数组,而显式指定的嵌套数组规格则要求精确匹配
数组规格
任何数组规格本身都组织为关联数组。
[
'key' => 'string',
'otherKey' => 'int'
]
例如是有效的规格
[
'key' => 'value',
'otherKey' => 42
]
当然,规格可以嵌套。
[
'key' => [
'first' => 'number',
'second' => 'bool'
]
]
与以下匹配
[
'key' => [
'first' => INF,
'second' => false
]
]
但(显然)不匹配
[
'key' => 'someString'
]
规格键可以通过类似 RegExp 的功能附加,以扩展匹配功能,即
{a,b}表示至少匹配 a 和最多匹配 b{,b}表示匹配 0 到 b{a,}表示匹配 a 到无穷大
+表示匹配一次或多次(等于{1,})*表示匹配 0 次或多次(等于{0,})?表示可选匹配(等于{0,1})
允许使用此 RegExp 类型集进行 0 次匹配的键可以显式设置为 null 或隐式删除。
当然,这些 RegExp 规则也可以应用于嵌套数组规格结构。
[
'key' => 'string',
'optional?' => 'int',
'any*' => [
'foo' => 'bool',
'bar' => [
'one+' => 'number!',
'two{3,5}' => 'number!'
]
]
]
匹配
[
'key' => 'value',
'optional' => 0,
'any' => [
[
'foo' => true,
'bar' => [
'one' => 123,
'two' => [456, 789, 321, 654]
]
], [
'foo' => false,
'bar' => [
'one' => [3.141592, 6.283185],
'two' => [1.414213, 2.718281, 1.618033]
]
]
]
]
以及
[
'key' => 'value',
'any' => [
'foo' => true,
'bar' => [
'one' => 123,
'two' => [1.1, 2, 3.3, 4, 5.5]
]
]
]
可以使用竖线 | 符号将多个类型连接起来。这不会与其他类型规则冲突。
[
'key' => 'string!|bool',
'otherKey' => 'int|array'
]
是有效的规格
[
'key' => 'element',
'otherKey' => 123
]
以及
[
'key' => true,
'otherKey' => 123
]
和
[
'key' => false,
'otherKey' => ['foo', 'bar']
]
可以使用键 __root 检查顶层顺序数组是否符合规格。这对于批量处理给定规格特别有用
[
'__root+' => [
'foo' => 'bool',
'bar?' => 'int'
]
]
匹配
[
[
'foo' => 'true',
'bar' => 0
], [
'foo' => 'true'
], [
'foo' => 'false',
'bar' => 42
]
]
冒号表示法
一些嗅探器,尤其是 StringSniffer、ObjectSniffer 和 MixedArraySniffer,支持通过使用 :: 来指定额外的嗅探数据。
这个冒号 "运算符" 支持多个重复参数。参数的效果由相应的嗅探器类指定。
对于 StringSniffer,冒号数据可以用来指定一个匹配的正则表达式 (RegExp)。除了使用 PHP 标准库中指定的 preg_match 进行的常规检查外,还会检查该 RegExp 的符合性。
[
'foo*' => 'string::^[A-Z][a-z]*$'
]
匹配
[
'foo' => ['Hello', 'World']
]
但不包括
[
'foo' => ['eHlo', 'World', '!']
]
请注意,如果尚未包含,正则表达式将自动用方便的 PCRE 边界符 (即 //) 括起来。
对于 ObjectSniffer,冒号数据可以用来指定实例类名。它们可以是完全命名的空间,但也会执行标准的 "短名" 检查。
[
'object' => 'class::MyClass'
]
匹配
[
'object' => new MyClass()
]
但不包括
[
'object' => new MyOtherClass()
]
也不包括
[
'object' => new stdClass()
]
请注意,可以使用相同的冒号 :: 运算符重复指定多个类。
[
'object' => 'class::MyClass::MyOtherClass'
]
考虑到两者
[
'object' => new MyClass()
]
和
[
'object' => new MyOtherClass()
]
对于 MixedArraySniffer,冒号数据可以用来指定是否需要关联数组或顺序数组。
[
'values' => 'array::sequential'
]
匹配
[
'values' => [1, 2, 'one', 'two', true, false]
]
但不包括
[
'values' => [
'key' => 'value'
]
]
而指定
[
'dict' => 'array::associative'
]
匹配
[
'dict' => [
'one' => 1,
'two' => 2
]
]
但不是上面提到的 values 示例。为了方便,已安装了常见的别名 seq 用于 sequential 和 assoc 用于 associative,所以
[
'members' => 'array::seq',
'relations' => 'array::assoc'
]
是一个有效的指定。如果指定了多个数组类型,将丢弃并嗅探为 false,或抛出异常。
示例
一旦我找到了不涉及我日常工作中机密数据的具有意义的示例,就会将示例添加到 Examples/ 目录中。