📜 ⬆️ ⬇️

Dependency Injection Introduction

Inversion is a simple and functional dependency injection container for PHP 5.3. Supports service-oriented architecture, links, PRS-0, and Composer .



You can install via packagist.org: granula / inversion or by downloading and adding a compatible bootloader to PRS-0.
')
$container = new Inversion\Container(); $container['foo'] = 'My\Class\Foo'; // ... $foo = $container('foo'); 


The above example shows the basic functionality of the container. We will analyze what is happening there.
In the first line create an instance of the container. In the second, we create an association between “foo” and the service that creates an instance of the “My \ Class \ Foo” class. What else can be written like this:
 $container->addService(new Service('My\Class\Foo'), 'foo'); 

The name "foo" comes second, because it can be omitted altogether. More details below.

In the third line, we get an instance of the object. What else can be written like this:
 $foo = $container('foo'); //  $foo = $container->get('foo'); //  $foo = $container['foo']->get(); //  $foo = $container->getService('foo')->get(); 

However, I recommend using the abbreviated version, although they are all valid.


Description of dependencies


By default, when a string is transferred to a container, it is understood as a class name and is substituted into the Inversion \ Servise service.
This service has several features and functions.
The first is a deferred download. Until you use it, the class will not be loaded.
Second, you can specify dependency on other services and parameters. I will explain with an example.
Suppose we have a class Bar, which depends on the classes One and Two:
 namespace My\Space; class One {} class Two {} class Bar { public function __construct(One $one, Two $two) { } } 

We describe this dependency in Inversion:
 use Inversion\Service; //... $container['one'] = 'My\Space\One'; $container['two'] = 'My\Space\Two'; $container['bar'] = new Service('My\Space\Bar', array($container['one'], $container['two'])); 

Now, when calling "bar", they will be created and substituted into the constructor. Actually it can be even easier. If instead of “one” and “two” specify their class names:
 $container['My\Space\One'] = 'My\Space\One'; $container['My\Space\Two'] = 'My\Space\Two'; $container['My\Space\Bar'] = new Service('My\Space\Bar'); // "new Service"   

This is a convenient way to describe dependencies when using interfaces:
 namespace My\Space; class One implements OneInterface {} class Two implements TwoInterface {} class Bar implements BarInterface { public function __construct(OneInterface $one, TwoInterface $two) { } } 


 $container['My\Space\OneInterface'] = 'My\Space\One'; $container['My\Space\TwoInterface'] = 'My\Space\Two'; $container['My\Space\BarInterface'] = 'My\Space\Bar'; 

In general, interface names can be omitted. They will be automatically derived from the classes:
 $container[] = 'My\Space\One'; $container[] = 'My\Space\Two'; $container[] = 'My\Space\Bar'; 

This is how simple it is.
However, you need to understand that in this case the classes will be immediately loaded to get the list of interfaces through reflection. Therefore, it is better to specify the interface name manually.


Other types of services


There are several services in the library, however you can create your own implementing Inversion \ ServiceInterface .

Closure


Class: Inversion \ Service \ Closure
Using:
 $container['closure'] = function () use ($container) { return new My\Class(); }; 

You can also specify dependencies:
 $container['closure'] = function (One $foo, Two $foo) use ($container) { return new My\Class(); }; 

As with Inversion \ Service, you can specify them explicitly:
 $container['closure'] = new Closure(function (One $foo, Two $foo) use ($container) { return new My\Class(); }, array($container['one'], $container['two'])); 


Factory


Class: Inversion \ Service \ Factory
Using:
 $container['factory'] = new Factory('My\ClassFactory', 'create'); 

You can also specify dependencies for the constructor explicitly by the third parameter.

Object


Class: Inversion \ Service \ Object
Using:
 $container['object'] = new My\Class(); 

or
 $container['object'] = new Object(new My\Class()); 


Prototype


Class: Inversion \ Service \ Prototype
Using:
 $container['prototype'] = new Prototype($object); 

Each call will create a new copy: clone $ object.

Data


Class: Inversion \ Service \ Data
Using:
 $container['data'] = new Data('what you want'); 

By default, all arrays are converted to Data services.
 $container['data'] = array(...); 

Equivalent to:
 $container['data'] = new Data(array(...)); 

Links to services


Inversion supports links. To get the link, refer to the container as an array:
 $container['foo'] = new Service(...); $ref = $container['foo']; //   . 

Thus, you can create an alias to any service:
 $container['My\Class\FooInterface'] = new Service('My\Class\Foo'); $container['foo'] = $container['My\Class\FooInterface']; //... $foo = $container('foo'); 

Now, if someone overwrites “My \ Class \ FooInterface”, then “foo” will still refer to this service:
 //... $container['My\Class\FooInterface'] = new Service('Another\FooImpl'); //... $foo = $container('foo'); // $foo instanseof Another\FooImpl 

You can even create links to links:
 $container['foo'] = 'My\Class\Foo'; $container['ref'] = $container['foo']; $container['ref2'] = $container['ref']; $container['ref3'] = $container['ref2']; //... $foo = $container('ref3'); // $foo instanseof My\Class\Foo $name = $container->getRealName('ref3'); // $name == 'foo' 

Expansion of services


For example, if we want to expand any service, then this method will not work. he will overwrite the first one:
 $container['My\Class\FooInterface'] = 'My\Class\Foo'; //... $container['My\Class\FooInterface'] = function (FooInterface $foo) { $foo->extendSome(...); return $foo; }; 

As a result, there will be a looping to avoid this, for expansion use the following function:
 $container['My\Class\FooInterface'] = 'My\Class\Foo'; //... $container->extend('My\Class\FooInterface', function (FooInterface $foo) { return new FooDecorator($foo); }); 

Tests


Inversion library is fully tested. Tests are in a separate repository ( granula / test ) to reduce the size of the library.

Like singleton


Inversion is designed completely without the use of static methods and singletons, but it is rarely useful to have a container as a singleton:
 $container = Inversion\Container::getInstanse(); 


Other implementations


Source: https://habr.com/ru/post/169187/


All Articles