Skip to content

Dependency injection

Dependency injection is provided by the NaN\DI namespace.

Terminal window
composer require aimfornan/nan-di

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,
]);

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,
);

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)
;

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) {
// ...
}

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);