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/
目录中。