Standard Core Libraries

SPL extensions, array utilities, error handlers, and more.

Introduction

Standard Core Libraries is sets of useful basic libraries and helpers. these libraries are used as part of core functionalities of Poirot Framework. The component are distributed under the "Poirot/Std" namespace and has a git repository, and, for the php components, a light autoloader and composer support. All Poirot components following the PSR-4 convention for namespace related to directory structure and so, can be loaded using any modern framework autoloader. 100% Test Coverage and fully testable by PHPUnit Test.

In Case You need any support or question use the links below:

Slack: getpoirot.slack.com https://join.slack.com/t/getpoirot/shared_invite/zt-dvfhkoes-h45XoKlyxamfhaHm6G4uSA

Arguments Resolver

It helps to automatically call a callable (function, method or closure) or create an instance of a class with providing necessary arguments from list of available options.

Resolver can resolve arguments by argument name, or type hint provided to the argument. Argument name has the most priority, if name is not match within provided options then try to match based on the type hint of argument by searching from the first element to last options and find the match.

function foo(array $array, stdClass $object, callable $callable, array $secondArray) {}

$ar = new ArgumentsResolver(new CallableResolver('foo'));
$args = $ar->withOptions([
    function () {},
    ['second' => ''],
    new stdClass(),
    'array' => [],
])->getResolvedArguments();

/*
[
  'array' => [],
  'object' => object(stdClass)
  'callable' => object(Closure)
  'secondArray' => ['second' => '']
]
*/

Class Instantiator

Create an instance of class and resolve the arguments needed to constructing object by available given options.

or simply use the global function available to create instance of class:

Callable Resolver

Allows to determine the arguments to pass to a function or method and call it. The input to the resolver can be any callable.

Usage:

Resolve to callable arguments as an array:

Call callable dynamically by list of available arguments: this will resolve the arguments list needed to execute callable and wrap it to the \Closure that can be invoked directly. The codes below is equivalent as the code block that you can find above.

or simply use the available global function helper:

Reflection Resolver

There is also an utility class which helps in creating a reflection instance: The input can be any callable.

Configurable

Configurable objects are classes which implemented ipConfigurable pact interface, which allow object to parse configuration properties from a resource to an iterator and build the object itself with this given properties.

Register custom config parser

Parser can be registered globally for classes which extends aConfigurable each registered parser should implement iConfigParser interface. here is an example of registering json parser for imaginary Application Configurable class.

Configurable setter

Built-in configurable which map whole properties to a setter method defined inside the class and feed them by calling setter method and associated value of given property.

This is the simple demonstration of what is expected of a configurable object:

Multi Parameter Setter Methods

If the setter method needs to have more than one value as a parameter the easiest way is to pass required parameters as an iterable or array to a method. with configurableSetter it's possible to define parameters needed for a setting as a separate arguments to the setter method.

Avoid configuration exceptions

Exceptions of type ConfigurationError expected to thrown when something is not correct with given configuration properties. for example when given property is unknown (UnknownConfigurationPropertyError) for configurable object or the given value has not correct type (ConfigurationPropertyTypeError).

During building object throwing these known exceptions can be eliminated and skipped.

Environment configuration

To ease apply different PHP runtime configurations at once the iEnvironmentContext interface is defined which can hold various possible runtime configuration values. This contexts can be considered as different environments with different setup for a specific purpose. such as Development, Test or Production setup.

Simple usage

Available configurations

Here is the list of available configuration provisioning attributes and their corresponding built-in php command:

Attribute

Value

Equivalent PHP Command

define_const

array(['const_name' => 'value'])

define((string) $const, $value);

display_errors

(int) 0, 1

ini_set('display_errors', $value);

display_startup_errors

(int) 0, 1

ini_set('display_startup_errors', $value);

env_global

array(['env_name' => 'value'])

$_ENV[$name] = $value; //simplified

error_reporting

(string) 'E_ALL' bitwise can't be used

(int) E_ALL & ~E_NOTICE

predefined constants

error_reporting(E_ALL);

html_errors

(int) 0, 1

ini_set('html_errors', $value);

time_zone

date_default_timezone_set('UCT')

max_execution_time

(int) 30

set_time_limit($seconds)

PreDefined Contexts

Development, Will enable all error reporting level to show to end-user.

Production, to mitigate all error messages to display to end user.

PhpServer, will give the current values from php server configuration.

Environment Context Registry

Environment context values can be override while registry provision configurations.

after applying environment context it's accessible from registry anytime.

Custom environment context

It's possible to register an actual context with different aliases naming or create a new context which implementing iEnvironmentContext interface. Alias naming of existing contexts:

Custom context implementation:

Error Handler

It's a wrapper around default php set_error_handler and set_exception_handler functions. it can be used to create a custom error handler that lets you control how PHP behave when some runtime errors happens. With different error types custom error handling can handle only errors were expecting and take the appropriate action based on that.

Simple usage

Custom error handler

ErrorHandler::handle takes the callable as it's second parameter, and it servers to notify PHP that if there are any php runtime errors. Callable expected to get \ErrorException object as all errors will converted to by error handler.

Error level handling

First argument of ErrorHandler lets you choose what errors should handled, and it works like the error_reporting directive in php.ini. However, it's important to remember that you can only have one active error handler at any time, not one for each level of error.

By default error handler will not catch errors that is silenced by error_reporting level otherwise we use a specific bit control flag ErrorHandler::E_ScreamAll

There is a special bit mask flag ErrorHandler::E_ScreamAll that can be added to error level handling to catch all errors if accrued regardless of what php error reporting level is.

Handle Exceptions

As exceptions terminate the execution flow there is no much control over Exception handling the only thing is triggering callable registered in chain.

Hydrator

Hydrator provide a mechanisms both for mostly extracting data sets from objects, as well as manipulating objects data. A simple example of when hydrators came handy is when user send form data from website these data can be in different naming as we expect in domain logic and probably doing some filter over data as they are not trusted usually.

Entity Hydrator

Entity Hydrator abstract basically separate manipulation and extraction to two different job, with defined setter methods hydrator object can be manipulated with given data set then based on the given data we have getter methods which is expected to filter and extract prepared data for next stage to receiver of data.

Register global input data parser: with data parsers it's possible to parse different data types to an iterator to feed into entity hydrators to related setter method.

Getters hydrator

extract data from an object with getter methods, generally getter hydrator will make an Reflection object of class find getter methods and iterate them by calling them method and return the sanitaized property name associated with the value returned from method call.

Some property methods can be excluded to not considered as data:

Excluding properties can be defined as well internally into class by notations:

IteratorWrapper

This iterator wrapper allows the conversion of anything that is Traversable into an Iterator. This class provide a wrapper around any php Traversable and adding extra functionalities to that.

Manipulating key and values

On iterator callback the returned value will considered as a current value of iterator item:

we also can change the key if we need to do this:

Filter items

With iterator wrapper we can skip unwanted items from the iterator with provide Closure control how we iterate over object.

Cutout items

Sometimes it's needed to stop iterating over items when specific conditions met before we get to the end of iterator items. like when we have limit on database result items.

Caching Iterator

As we have built-in support for CachingIterator but IteratorWrapper itself comes with the internal caching support to the iteration. Some times you have an iterator which is not iterable multiple times for instance it could be the case when you fetch result from databases like MangoDB which you cant rewind the iteration. here is the example can illustrating this better:

MutexLock

The Mutex allows mutual execution of concurrent processes in order to prevent "race conditions". This is achieved by using a "lock" mechanism. Each possibly concurrent thread cooperates by acquiring a lock before accessing the corresponding data.

Usage example:

How to instantiate lock for specific resource:

here we created an instantiate of lock object which is try to make lock file on given $lockDir path, the $realm is an indicator and unique name to our lock resource. MutexLock::giveLockDirPath is an Immutable method so when we gave the path we couldn't change the value later on.

Object can acquire lock multiple times

When object is already acquire lock on resource all further tries to lock from same object will be success:

Different lock object instances can't acquire lock on same resource

If we create different lock objects with same setup lock will not acquired on second calls if resource is already got locked.

Releasing lock, cleanup and destructing object

As the crash could happen to PHP while we acquired lock the resource might kept as locked as execution didn't reach the __destruct method of lock object. we always allow MutexLock to release on resources. We need a system that cleans the garbage in case of crash, just like PHP does for everything else. register_shutdown_function() could cover the cases of exit(), die() and other exceptions in the code code, but it wouldn’t be enough for a crash or an interruption.

Expiration TTL on lock

The TTL expiration on seconds amount of time can be defined to keep lock on resource.

ResponderChain

The ResponderChain allows to run multiple callable one after other and pass the result from each callable to others to attain to the final result.

Default Chaining Result Behaviour

Merging values

By default if value returned from callable is array or StdArray object will get merged to previous result regardless if the previous result is array, StdArray or not.

Replacing values

Any value other than array or StdArray returned by callable will replace the result from previous callable regardless if the previous result is arrayor not.

Another example to demonstrate merge and replace together:

Key Value Pair Result

The KeyValueResult object can be returned by the callable to indicate that value is an key, value pair result which a key holding the value associated with that. The KeyValueResult will not get merged by the previous value and always replace the last one and will cast to a single key associative array at the end.

Instead regular array this result won't get merged by last result from chain:

Aggregate Result

The AggregateResult will accept a variadic arguments of any data result implementation or any PHP default data type and merge them together, the final result is a multi key / value pair array.

The AggregateResult will not get merged by the previous value and always replace the last result.

The AggregateResult respond result won't get merged by last result from chain:

Merge Result

When result from callable is MergeResult will merge the data from last result, it's similar to simple array type behaviour when it's returned by callable.

Passing Parameters Through Call Chain

After each callable execution returned result get merged to params and will get resolved by type and name of argument to next callable.

Define Default Parameters

default parameters can be set on creation time, these parameters can be resolved to callable which required the parameter by defining an argument with same type or name to callable. to read more about resolving arguments see ArgumentsResolver.

Parameters get updated based on each result from callable

Every result returned by each callable will get merged to the default parameters and will replace if the current parameters with same name exists then these parameters can be resolved to next callable.

Exception Handling

With onFailure method the callable can be assigned to a callable chain which will be executed, the \Exception which is thrown and other parameters will be resolved to given callable.

Validator abstraction

Validation is a very common task while we dealing with Data, Data can come from forms submitted by users or data before it is written into a database or passed to other web service. Any object can implement Validator abstraction interface and trait which makes validation task transparent by providing an abstraction layer to generalize the validation. any Validation libraries can still be use out of the box to ease validation task or just simple php code block.

Usage example

The only task of objects implementing validation abstract is to add ValidationError object as error(s) which found during validation.

Error chain

Each error caught by validator will chained together as an exception which is traversable by getting the previous exception chain.

Error message processor

Validation error messages are usually shows to users directly, depends of different scenarios we might wanted to show different messages to end user like translating error messages. There is some samples of error messages processors which give you the whole idea of how to use them. Default registered message processor will replace %param% and %value% with ValidatorError into error message.

Any custom message processor can be attached statically to the ValidationError class.

Last updated

Was this helpful?