Dependency Injection

    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 it through 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 a container. Let's see what happens there.
    In the first line we create an instance of the container. In the second, we create an association between "foo" and the service creating an instance of the class "My \ Class \ Foo". What else can be written like this:
    $container->addService(new Service('My\Class\Foo'), 'foo');
    

    The name “foo” comes second, as 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 shortened version, although all of them are valid.


    Dependency Description


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

    We describe this dependency in Inversion:
    useInversion\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 you call bar, they will be created and substituted into the constructor. Actually it can be even easier. If instead of “one” and “two” indicate 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:
    namespaceMy\Space;
    classOneimplementsOneInterface{}
    classTwoimplementsTwoInterface{}
    classBarimplementsBarInterface{
        publicfunction__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, the names of the interfaces can be omitted. They will be automatically obtained from the classes:
    $container[] = 'My\Space\One';
    $container[] = 'My\Space\Two';
    $container[] = 'My\Space\Bar'; 
    

    Just like that.
    However, you need to understand that in this case, the classes will be immediately loaded to get a 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 by implementing Inversion \ ServiceInterface .

    Closure


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

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

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


    Factory


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

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

    Object


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

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


    Prototype


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

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

    Data


    Class: Inversion \ Service \ Data
    Usage:
    $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(...));
    

    Service Links


    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 rewrites “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'

    Service extension


    For example, if we want to expand some 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 loop to avoid this, use the following function to expand:
    $container['My\Class\FooInterface'] = 'My\Class\Foo';
    //...
    $container->extend('My\Class\FooInterface', function(FooInterface $foo){
        returnnew FooDecorator($foo);
    });
    

    Tests


    The Inversion library is fully tested. Tests are located 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 singleton, however it is rarely useful to have a container like a singleton:
    $container = Inversion\Container::getInstanse();
    


    Other implementations


    • Symfony Dependency Injection is a powerful and heavy dependency injection library. Has good documentation.
    • Pimple is a simple and very lightweight (just one file) “container” from the creator of Symfony.

    Also popular now: