kuria / options
根据指定的选项集解决结构化数组
Requires
- php: >=7.1
- kuria/debug: ^4.0
Requires (Dev)
- kuria/dev-meta: ^0.6
This package is auto-updated.
Last update: 2024-09-22 16:39:47 UTC
README
根据指定的选项集解决结构化数组(例如配置)。
内容
功能
- 类型验证
- 类型列表
- 可空选项
- 选项
- 默认值
- 延迟默认值(可能依赖于其他选项)
- 自定义验证器和规范器
- 嵌套选项(多维数组)
- 自定义解析器上下文
要求
- PHP 7.1+
使用方法
解决选项
使用 Resolver
根据指定的选项解决数组。
resolve()
方法返回一个 Node
实例,可以将其作为数组访问。见 与节点实例一起工作。
如果传入的值无效,将抛出 ResolverException
。见 处理验证错误。
<?php use Kuria\Options\Resolver; use Kuria\Options\Option; // create a resolver $resolver = new Resolver(); // define options $resolver->addOption( Option::string('path'), Option::int('interval')->default(null) ); // resolve an array $node = $resolver->resolve([ 'path' => 'file.txt', ]); var_dump($node['path'], $node['interval']);
输出
string(8) "file.txt" NULL
与 Node
实例一起工作
默认情况下,Resolver->resolve()
返回一个具有已解决选项的 Node
实例。
Node
实现了ArrayAccess
,因此可以使用数组语法访问单个选项:$node['option']
延迟默认值 在读取该选项(或调用
toArray()
时)解决一次嵌套的 节点选项 也作为
Node
实例返回(如果您需要专门使用数组,请使用
$node->toArray()
)
解析器上下文
Resolver->resolve()
接受第二个参数,该参数可以是传递给所有验证器、规范化和延迟默认闭包的额外参数数组。值可以是任何类型。
use Kuria\Options\Node; use Kuria\Options\Option; use Kuria\Options\Resolver; $resolver = new Resolver(); $resolver->addOption( Option::string('option') ->normalize(function (string $value, $foo, $bar) { echo 'NORMALIZE: ', $foo, ', ', $bar, "\n"; return $value; }) ->validate(function (string $value, $foo, $bar) { echo 'VALIDATE: ', $foo, ', ', $bar, "\n"; }), Option::string('optionWithLazyDefault') ->default(function (Node $node, $foo, $bar) { echo 'DEFAULT: ', $foo, ', ', $bar, "\n"; return 'value'; }) ); $options = $resolver->resolve( ['option' => 'value'], ['context argument 1', 'context argument 2'] )->toArray();
输出
NORMALIZE: context argument 1, context argument 2 VALIDATE: context argument 1, context argument 2 DEFAULT: context argument 1, context argument 2
定义选项
术语
- 叶选项
- 选项树中不包含子选项的选项。
- 节点选项
- 通过
Option::node()
或Option::nodeList()
定义的选项。它们是选项树中的分支。 - 子选项
- 嵌套在节点选项内的任何选项。它可以是叶选项或节点选项。
选项工厂
Option
类提供了一些静态工厂来创建选项实例。
选项配置
可以通过以下方法进一步配置选项实例。
所有方法都实现了流畅的接口,例如
<?php use Kuria\Options\Option; Option::string('name') ->default('foo') ->nullable();
required()
使选项成为必需的(并删除之前设置的任何默认值)。
default($default)
使选项可选并指定默认值。
延迟默认值(仅限于叶节点)
要指定延迟默认值,请传递以下签名的闭包
<?php use Kuria\Options\Node; use Kuria\Options\Option; Option::string('foo')->default(function (Node $node) { // return value can also depend on other options return 'default'; });
当需要默认值时,将调用闭包,并将返回值存储以供以后使用(因此它不会调用超过一次)。
注意
必须提供类型提示的Node
参数。不兼容签名的闭包将被视为默认值本身,并按原样返回。
注意
节点选项不支持延迟默认值。
提示
可以将额外的参数传递给所有延迟默认闭包。请参阅解析器上下文。
nullable()
使选项可空,除了指定的类型外,还可以接受NULL
。
notNullable()
使选项不可空,不接受NULL
。
注意
默认情况下,选项不可空。
allowEmpty()
允许将空值传递给此选项。
注意
默认情况下,选项接受空值。
notEmpty()
使选项拒绝空值。
如果PHP的empty()返回TRUE
,则认为值是空的。
normalize(callable $normalizer)
将规范器附加到选项。规范器应接受一个值并返回规范化后的值,或者在失败时抛出Kuria\Options\Exception\NormalizerException
。
请参阅规范器和验证器值类型。
- 规范器在由
validate()
定义的验证器之前调用。 - 规范器按附加的顺序调用。
- 如果值的类型无效,则不调用规范器。
- 选项规范化的顺序未定义(但节点选项按子节点优先顺序进行规范化)。
<?php use Kuria\Options\Resolver; use Kuria\Options\Option; $resolver = new Resolver(); $resolver->addOption( Option::string('name')->normalize('trim') ); var_dump($resolver->resolve(['name' => ' foo bar ']));
输出
object(Kuria\Options\Node)#7 (1) { ["name"]=> string(7) "foo bar" }
注意
要规范化根级别上的所有选项,请使用$resolver->addNormalizer()
定义一个或多个规范器。
提示
可以使用规范器将节点转换为自定义对象,因此您不必与匿名Node
对象一起工作。
提示
可以将额外的参数传递给所有规范器。请参阅解析器上下文。
validate(callable $validator)
将验证器附加到选项。验证器应接受并验证一个值。
- 验证器在由
normalize()
定义的规范器之后调用。 - 验证器按附加的顺序调用。
- 如果值的类型无效或其规范化失败,则不调用验证器。
- 如果验证器返回一个或多个错误,则不会调用该选项的其他验证器。
- 选项验证的顺序未定义(但节点选项按子节点优先顺序进行验证)。
验证器应返回以下之一
NULL
或空数组,如果没有错误- 错误作为字符串、字符串数组或错误实例
<?php use Kuria\Options\Exception\ResolverException; use Kuria\Options\Resolver; use Kuria\Options\Option; $resolver = new Resolver(); $resolver->addOption( Option::string('email')->validate(function (string $email) { if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) { return 'must be a valid email address'; } }) ); try { var_dump($resolver->resolve(['email' => 'this is not an email'])); } catch (ResolverException $e) { echo $e->getMessage(), "\n"; }
输出
Failed to resolve options due to following errors: 1) email: must be a valid email address
注意
要在根级别验证所有选项,请使用 $resolver->addValidator()
定义一个或多个验证器。
提示
可以向所有验证器传递额外的参数。请参阅 解析器上下文。
支持类型
NULL
- 任何类型"bool"
"int"
"float"
"number"
- 整数或浮点数"numeric"
- 整数、浮点数或数值字符串"string"
"array"
"iterable"
- 数组或Traversable
实例"object"
"resource"
"scalar"
- 整数、浮点数、字符串或布尔值"callable"
其他任何类型都被视为类名,接受给定类或接口(或其子类)的实例。
将选项定义为可空也将接受 NULL
值。请参阅 可空。
规范化和验证器值类型
传递给正常化器和验证器的值的类型取决于选项的类型。
Option::list()
、Option::choiceList()
- 值数组Option::node()
-Node
实例Option::nodeList()
-Node
实例数组- 其他 - 依赖于选项的类型(
string
、int
等)
注意
正常化器可以在将值传递给后续的正常化器和验证器之前修改或替换该值(包括其类型)。
节点选项
节点选项接受指定选项的数组。使用它们可以解析更复杂的结构。
- 节点选项是迭代地解析的(不使用递归)
- 某些配置与节点选项的行为不同,请参阅 选项配置
<?php use Kuria\Options\Option; use Kuria\Options\Resolver; $resolver = new Resolver(); $resolver->addOption( Option::string('username'), Option::node( 'personalInformation', Option::int('birthYear'), Option::int('height')->default(null), Option::float('weight')->default(null) ), Option::nodeList( 'securityLog', Option::string('action'), Option::int('timestamp'), Option::node( 'client', Option::string('ip'), Option::string('userAgent') ) ) );
处理验证错误
如果失败,Resolver->resolve()
方法会抛出 Kuria\Options\Exception\ResolverException
。
可以通过在异常对象上调用 getErrors()
来检索特定错误。
<?php use Kuria\Options\Resolver; use Kuria\Options\Exception\ResolverException; use Kuria\Options\Option; $resolver = new Resolver(); $resolver->addOption( Option::string('name'), Option::int('level'), Option::int('score') ); try { $resolver->resolve([ 'name' => null, 'level' => 'not_a_string', 'foo' => 'bar', ]); } catch (ResolverException $e) { foreach ($e->getErrors() as $error) { echo $error->getFormattedPath(), "\t", $error->getMessage(), "\n"; } }
输出
name string expected, but got NULL instead level int expected, but got "not_a_string" instead score this option is required foo unknown option
忽略未知键
可以通过调用 $resolver->setIgnoreUnknown(true)
来配置 Resolver
以忽略未知键。
- 对于未知键将不再抛出
UnknownOptionError
- 这也适用于嵌套选项
- 未知键将出现在解析后的选项中
集成选项解析器
可以使用 StaticOptionsTrait
来轻松地向类添加静态选项支持。
它还有一个额外的优点,即在类的多个实例中缓存和重用解析器。如果需要,可以通过调用 Foo::clearOptionsResolverCache()
来清除缓存。
<?php use Kuria\Options\Integration\StaticOptionsTrait; use Kuria\Options\Node; use Kuria\Options\Option; use Kuria\Options\Resolver; class Foo { use StaticOptionsTrait; /** @var Node */ private $config; function __construct(array $options) { $this->config = static::resolveOptions($options); } protected static function defineOptions(Resolver $resolver): void { $resolver->addOption( Option::string('path'), Option::bool('enableCache')->default(false) ); } function dumpConfig(): void { var_dump($this->config); } }
实例化示例
<?php $foo = new Foo(['path' => 'file.txt']); $foo->dumpConfig();
输出
object(Kuria\Options\Node)#8 (2) { ["path"]=> string(8) "file.txt" ["enableCache"]=> bool(false) }