adeptoas/sniff-array

用于检查数组规格一致性的工具

1.7.1 2019-07-31 16:51 UTC

This package is auto-updated.

Last update: 2024-08-29 03:57:22 UTC


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

返回一个适合检查符合 typeSplSniffer 子类。

sniff(mixed $val, bool $isStrict = false): bool

检查 val 是否符合当前 SplSniffer 实例类型所隐含的规格。isStrict 指定是否应将某些边缘情况视为有效(请参阅下面的进一步说明)

规格

基本类型

此库提供的基本类型识别包括

  • 字符串
  • 整数
  • 数字
  • 布尔值
  • 混合
  • 数组
  • 对象

一些常见别名也已实现

  • 布尔值 => 布尔
  • 整数 => 整数
  • 数字 => 数字
  • 任何 => 混合
  • 空 => 空值
  • 类 => 对象

严格的规格通过类型后跟感叹号 ! 来表示,并缩小可接受值的范围。特别是

  • 字符串!不接受空字符串 ''
  • int!不接受 0
  • 数字!不接受 0NAN
  • 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
    ]
]

冒号表示法

一些嗅探器,尤其是 StringSnifferObjectSnifferMixedArraySniffer,支持通过使用 :: 来指定额外的嗅探数据。

这个冒号 "运算符" 支持多个重复参数。参数的效果由相应的嗅探器类指定。

对于 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 用于 sequentialassoc 用于 associative,所以

[
    'members'   =>  'array::seq',
    'relations' =>  'array::assoc'
]

是一个有效的指定。如果指定了多个数组类型,将丢弃并嗅探为 false,或抛出异常。

示例

一旦我找到了不涉及我日常工作中机密数据的具有意义的示例,就会将示例添加到 Examples/ 目录中。