Dependency injection
Dependency injection is provided by the NaN\DI namespace.
Installation
Section titled “Installation”composer require aimfornan/nan-diServices
Section titled “Services”To deal with classes, NaN provides the NaN\DI\Container class, which is a PSR-11-compatible container.
Services are registered through its constructor.
It can accept fully-qualified class names, closures, and single instances as values.
Single instances are used when you need to return the same instance every time.
So long as the container provides the necessary dependencies, constructing classes from fully-qualified names for classes that depend on other classes is a simple matter. When more complex setups are needed, that’s where closures come in. Closures can access other services through dependency injection.
use \NaN\DI\Container;
$services = new Container([ SomeInterface::class => SomeClass::class,]);use \NaN\DI\Container;
$services = new Container([ SomeInterface::class => function ( SomeOtherInterface $dependency, ) { // Some boilerplate...
return new SomeClass( $dependency, ...$args_from_boilerplate, ); }, SomeOtherInterface::class => SomeOtherClass::class,]);use \NaN\DI\Container;
$services = new Container([ SomeInterface::class => new SomeClass(...$args),]);The NaN\DI\Container class is designed to be immutable.
Call the withService method to add extra services.
/** @var \NaN\DI\Container $container */$container = $container->withService( SomeOtherInterface::class, SomeOtherClass::class,);Delegation
Section titled “Delegation”NaN provides the NaN\DI\DelegatesContainer class to support delegation.
Delegates are PSR-11-compatible containers that are used as secondary sources.
When the parent container lacks a service, delegate containers can help fill in the gaps.
This helps to maintain internal consistency.
Priority is based on insertion.
The NaN\DI\DelegatesContainer class is designed to be immutable.
It functions the same way as the NaN\DI\Container class, with the added support for delegation.
/** * @var \Psr\Container\ContainerInterface[] $containers * @var array $services */$container = new DelegatesContainer($services) ->withDelegates(...$containers);Extending the PSR-11 standard
Section titled “Extending the PSR-11 standard”The PSR-11 standard rejects any attempt at extending the standard
to include the ability to add services to containers.
To help fill the gap in the PSR-11 standard,
we provide the NaN\DI\Interfaces\ContainerSetterInterface interface.
The NaN\DI\Container class implements this interface.
use NaN\DI\Interfaces\ContainerSetterInterface;
// Check if container supports setting services!if ($container instanceof ContainerSetterInterface) { // ...}For delegates, there is the NaN\DI\Interfaces\ContainerDelegatesInterface interface.
This interface extends the NaN\DI\Interfaces\ContainerSetterInterface interface.
use \NaN\DI\Interfaces\ContainerDelegatesInterface;
// Check if container supports adding delegates!if ($container instanceof ContainerDelegatesInterface) { // ...}Autowiring
Section titled “Autowiring”NaN provides the NaN\DI\Arguments class to perform autowiring.
It supports resolving arguments for closures, class constructors and class methods.
It can resolve arguments for most parameter cases.
use \NaN\DI\{Arguments,Container};
$closure = function ( int $id, SomeInterface $some_class,) { // Do something...};
$args = Arguments::fromCallable($closure);$container = new Container([ SomeInterface::class => SomeClass::class,]);
// Automatically converts values to the required data type!$resolved = $args->resolve( ['id' => '1'], $container,);
$closure(...$resolved);use \NaN\DI\Arguments;
$args = Arguments::fromClassConstructor(\DateTime::class);$resolved = $args->resolve();
$dt = new \DateTime(...$resolved);use \NaN\DI\Arguments;
$args = Arguments::fromClassMethod(SomeClass::class, 'someMethod');$resolved = $args->resolve();
/** @var SomeClass $obj */$obj->someMethod(...$resolved);