Avris

This is a lite version. See full website.


Avris Container

A dependency injection container with autowiring

Installation

composer require avris/container

Usage

Basics

Container resolves dependencies between defined services, in order to simplify the development process, avoid duplication of code, facilitate interoperability and improve maintainability and testability. See: Dependency Injection pattern.

$parameterProvider = new SimpleParameterProvider(['ROOT_DIR' => __DIR__]);
// parameter provider is optional

$container = new Container($parameterProvider);

$container->set('number', 4);
$container->set(Foo::class, new Foo);
$container->setDefinition(Bar::class, [
    'arguments' => [
        '$foo' => '@' . Foo::class,
        '$dir' => '%ROOT_DIR%/bar',
        '$number' => '@number',
        '$float' => 69.123,
    ],
    'public' => true,
]);
$container->setDefinition(BarInterface::class, Bar::class); // alias

$container->get('number');              // 4
$container->get(Foo::class);            // new Foo
$container->get(BarInterface::class);   // new Bar(new Foo, __DIR__ . '/bar', 4, 69.123)
$container->getParameter('ROOT_DIR');   // __DIR__

Options

ContainerCompiler: autowiring and autoconfiguration

Usually it’s obvious, which service should be injected into another. For instance when your service has a constructor argument Psr\Cache\CacheItemPoolInterface $cache, and the container does have a service named Psr\Cache\CacheItemPoolInterface, then explicitly writing ['arguments' => ['$cache' => '@Psr\Cache\CacheItemPoolInterface'] is redundant. You can always specify the dependencies manually, then autowiring won't overwrite them.

Autowiring is not magic – it just follows simple rules to determine, which service should be injected into the constructor:

Autoconfiguration is another way to make your life simpler. For instance, if you’re using Twig, you might want all the classes in your code that extend Twig\Extension\AbstractExtension to be automatically registered as twig extension. Autoconfiguration lets you define what default config (tags, public etc.) should be added to them.

To use autowiring and autoconfiguration, run the ContainerCompiler:

$container = new Container;

$services = [
    'App\' => [
        'dir' => '%MODULE_DIR%/src/',
        'exclude' => ['#^Entity/#'],
    ],

    'App\Foo' => [
        'arguments' => [
            '$bar' => 5,
        ],
    ],

    'App\Bar' => [
        'public' => true,
    ],
];

$autoconfiguration = [
    'Twig\Extension\AbstractExtension' => [
        'tags' => ['twigExtension'],
    ],
];

$definitions = new ContainerCompiler(
    $container,
    $services,
    $autoconfiguration
))->compile();

/** @var ServiceDefinition $definition */
foreach ($definitions as $name => $definition) {
    if (!$container->has($name)) {
        $container->setDefinition($name, $definition);
    }
}

In this example, the whole %MODULE_DIR%/src/ except for (the /src/Entity dir) will be scanned for PHP files and all the found classes will be autowired as private services. If some of them are not used and not public, they will be removed from the container.

Compiling the container has no impact on performance on production environment, as long as you cache the result of compile().

ServiceLocator

Service locator restricts access to services in the container only to a selected list of names:

$container = new Container();
$container->set('foo', 'abc');
$container->set('bar', 'def');
$container->set('secret', 'XYZ');

$locator = new ServiceLocator($container, ['foo', 'bar']);

$locator->get('foo');     // 'abc'
$locator->get('bar');     // 'def'
$locator->get('secret');  // Exception

ContainerAssistedBuilder

ContainerAssistedBuilder can be used to join together a couple of ContainerBuilderExtensions which encapsulate a set of service definitions that form a library together. For an example, see Avris Localisator.

Micrus

This container was originally built as a part of the Micrus framework.


Tags: