Download the PHP package kuria/options without Composer
On this page you can find all versions of the php package kuria/options. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download kuria/options
More information about kuria/options
Files in kuria/options
Package options
Short Description Resolve structured arrays according to the specified set of options
License MIT
Informations about the package options
Options #######
Resolve structured arrays (e.g. configuration) according to the specified set of options.
:depth: 4
Features
- type validation
- typed lists
- nullable options
- choices
- default values
- lazy defaults (that may depend on other options)
- custom validators and normalizers
- nested options (multi-dimensional arrays)
- custom resolver context
Requirements
- PHP 7.1+
Usage
Resolving options
Use Resolver
to resolve arrays according to the specified options.
The resolve()
method returns an instance of Node
, which can be
accessed as an array. See Working with Node instances.
If the passed value is invalid, ResolverException
will be thrown.
See Handling validation errors.
// 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']);
Output:
string(8) "file.txt"
NULL
Working with Node
instances
By default, Resolver->resolve()
returns a Node
instance with the resolved options.
Node
implementsArrayAccess
, so the individual options can be acessed using array syntax:$node['option']
- lazy default values are resolved once that
option is read (or when
toArray()
is called) - nested node options are also returned as
Node
instances (if you need to work exclusively with arrays, use$node->toArray()
)
Resolver context
Resolver->resolve()
accepts a second argument, which may be an array of additional arguments
to pass to all validators, normalizers and lazy default closures. The values may be of any type.
$resolver = new Resolver();
$resolver->addOption( Option::string('option') ->normalize(function (string $value, $foo, $bar) { echo 'NORMALIZE: ', $foo, ', ', $bar, "\n";
return $value;
lidate(function (string $value, $foo, $bar) { echo 'VALIDATE: ', $foo, ', ', $bar, "\n";
string('optionWithLazyDefault') fault(function (Node $node, $foo, $bar) { echo 'DEFAULT: ', $foo, ', ', $bar, "\n";
return 'value';
);
$options = $resolver->resolve( ['option' => 'value'], ['context argument 1', 'context argument 2'] )->toArray();
Output:
NORMALIZE: context argument 1, context argument 2
VALIDATE: context argument 1, context argument 2
DEFAULT: context argument 1, context argument 2
Defining options
Terminology
leaf option An option in the option tree that does not contain children.
node option
An option defined via Option::node()
or Option::nodeList()
.
They are branches in the option tree.
child option Any option nested inside a node option. It can be either leaf or a node option.
Option factories
The Option
class provides a number of static factories to create option instances.
Factory | Description |
Option::any($name) | Mixed option that accepts all value types. NULL is accepted only if the option is nullable. |
Option::bool($name)
Boolean option.
Option::int($name)
Integer option.
Option::float($name)
Float option.
Option::number($name)
Number option that accepts integers and floats.
Option::numeric($name)
Numeric option that accepts integers, floats
and numeric strings.
Option::string($name)
String option.
Option::array($name)
Array option. The individual values are not validated.
Option::list($name, $type)
List option that accepts an array with values of the
specified type. Each value is validated and must not
be NULL
. See Supported types.
Option::iterable($name)
Iterable option that accepts both arrays and Traversable
instances. The individual values are not validated.
Option::object($name)
Object option.
Option::object($name, $className)
Object option that only accepts instances of the given
class or interface (or their descendants).
Option::resource($name)
Resource option.
Option::scalar($name)
Scalar option that accepts integers, floats, strings
and booleans.
Option::choice($name, ...$choices)
Choice option that accepts one of the listed values only
(compared in strict mode).
Option::choiceList($name, ...$choices)
Choice list option that accepts an array consisting of
any of the listed values (compared in strict mode).
Duplicates are allowed. NULL
values are not allowed.
Option::node($name, ...$options)
Node option that accepts an array of the specified options.
See Node options.
Option::nodeList($name, ...$options)
Node list option that accepts an array of arrays of the
specified options. See Node options.
========================================== ===================================================
Option configuration
Option instances can be configured further by using the following methods.
All methods implement a fluent interface, for example:
Option::string('name') ->default('foo') ->nullable();
required()
Makes the option required (and removes any previously set default value).
- a leaf option is required by default
- a node option is not required by default, but having
a required child option will make it required
(unless the node option itself defaults to
NULL
).
default($default)
Makes the option optional and specifies a default value.
- specifying
NULL
as the default value also makes the option nullable - default value of a leaf option is not subject to validation or normalization and is used as-is
- default value of a node option must be an array or
NULL
and is validated and normalized according to the specified child options
Lazy default values (leaf-only)
To specify a lazy default value, pass a closure with the following signature:
Option::string('foo')->default(function (Node $node) { // return value can also depend on other options return 'default'; });
Once the default value is needed, the closure will be called and its return value stored for later use (so it will not be called more than once).
nullable()
Make the option nullable, accepting NULL
in addition to the specified type.
notNullable()
Make the option non-nullable, not accepting NULL
.
allowEmpty()
Allow empty values to be passed to this option.
notEmpty()
Make the option reject empty values.
A value is considered empty if PHP's empty()
returns TRUE
.
normalize(callable $normalizer)
Append a normalizer to the option. The normalizer should accept a value
and return the normalized value or throw Kuria\Options\Exception\NormalizerException
on failure.
See Normalizer and validator value types.
- normalizers are called before validators defined by
validate()
- normalizers are called in the order they were appended
- normalizers are not called if the type of the value is not valid
- the order in which options are normalized is undefined (but node options are normalized in child-first order) $resolver = new Resolver(); $resolver->addOption( Option::string('name')->normalize('trim') ); var_dump($resolver->resolve(['name' => ' foo bar ']));
Output:
object(Kuria\Options\Node)#7 (1) {
["name"]=>
string(7) "foo bar"
}
validate(callable $validator)
Append a validator to the option. The validator should accept and validate a value.
- validators are called after normalizers defined by
normalize()
- validators are called in the order they were appended
- validators are not called if the type of the value is not valid or its normalization has failed
- if a validator returns one or more errors, no other validators of that option will be called
- the order in which options are validated is undefined (but node options are validated in child-first order)
The validator should return one of the following:
NULL
or an empty array if there no errors- errors as a
string
, an array of strings or Error instances $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"; }
Output:
Failed to resolve options due to following errors:
1) email: must be a valid email address
Supported types
NULL
- any type"bool"
"int"
"float"
"number"
- integer or float"numeric"
- integer, float or a numeric string"string"
"array"
"iterable"
- array or an instance ofTraversable
"object"
"resource"
"scalar"
- integer, float, string or a boolean"callable"
Any other type is considered to be a class name, accepting instances of the given class or interface (or their descendants).
An option defined as nullable will also accept a NULL
value. See nullable().
Normalizer and validator value types
The type of the value passed to normalizers and validators depend on the type of the option.
Option::list()
,Option::choiceList()
- an array of valuesOption::node()
- aNode
instanceOption::nodeList()
- an array ofNode
instances- other - depends on the type of the option (
string
,int
, etc.)
Node options
Node options accept an array of the specified options. With them it is possible to resolve more complex structures.
- node options are resolved iteratively (without recursion)
- certain configuration behaves differently with node options, see Option configuration $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') ) ) );
Handling validation errors
The Resolver->resolve()
method throws Kuria\Options\Exception\ResolverException
on failure.
The specific errors can be retrieved by calling getErrors()
on the exception object.
$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"; } }
Output:
name string expected, but got NULL instead
level int expected, but got "not_a_string" instead
score this option is required
foo unknown option
Ignoring unknown keys
The Resolver
can be configured to ignore unknown keys by calling
$resolver->setIgnoreUnknown(true)
.
UnknownOptionError
will no longer be raised for unknown keys- this applies to nested options as well
- the unknown keys will be present among the resolved options
Integrating the options resolver
The StaticOptionsTrait
can be used to easily add static option support
to a class.
It has the added benefit of caching and reusing the resolver in multiple
instances of the class. If needed, the cache can be cleared by calling
Foo::clearOptionsResolverCache()
.
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); }
}
Instantiation example:
$foo->dumpConfig();
Output:
object(Kuria\Options\Node)#8 (2) {
["path"]=>
string(8) "file.txt"
["enableCache"]=>
bool(false)
}