2017 © Pedro Peláez
 

library container

Lean PSR11 compatible dependency injection container

image

ecfectus/container

Lean PSR11 compatible dependency injection container

  • Saturday, October 1, 2016
  • by leemason
  • Repository
  • 1 Watchers
  • 1 Stars
  • 10 Installations
  • PHP
  • 2 Dependents
  • 0 Suggesters
  • 0 Forks
  • 1 Open issues
  • 1 Versions
  • 0 % Grown

The README.md

Container

Build Status, (*1)

Lean PSR11 (draft) compatible dependency injection container., (*2)

Inspired by both illuminate/container and league/container this container has a few advantages., (*3)

Low memory footprint

This is a very lazy container, binding services into it simply stores to its internal definition (which is an array, not an object)., (*4)

No objects are created, no parameters are instantiated, it simply stores the callback., (*5)

Alias callbacks are only called if/when the alias is requested by the ::get($alias) method., (*6)

Callback injection without reflection

illuminate/container offers up the entire container instance to callbacks, while league/container returns a definition were you can add arguments in a fluent manner., (*7)

The problem with this is either you are passing an entire container object to a callback that may not need much from it, consuming memory., (*8)

Or you are creating additional objects to store definitions, again consuming memory., (*9)

The solution is inspired by laravels routing component, provide an array as the callback:, (*10)

//this is just registering a normal callback which can optionally accept the container instance.
$container->bind(SomeClassInterface::class, function($container){//optionally get the passed in container, this is default
    return new SomeImplementation();
});


//this method allows you to define the whole dependency list for the callback
//by passing an array with the callback as the first item, and what needs to be passed to it as the rest of the array
//this allows for saving in both speed and memory usage.
$container->bind(SomeClassInterface::class, [function(A $a, B $b){
    return new SomeImplementation();
}, A::class, B::class]);

We have found even testing with as little as 5 dependant classes this method of providing the dependency list to be TWICE as fast and has no reflection needs., (*11)

Usage

The container conforms the current PSR11 container spec (in draft), so basic usage is as follows:, (*12)

$container = new Ecfectus\Container\Container();
//optionally include a reflection based delegate (only used if no registration exists, this is required if you plan on using the service provider container as well)
$container->delegate(new Ecfectus\Container\ReflectionContainer());

//optionally include the service provider container
$serviceProviderContainer = new ServiceProviderContainer();
$container->delegate($serviceProviderContainer);

//if registered add service providers either on the delegated container OR on the main container via the use of magic methods
$serviceProviderContainer->addServiceProvider(\Name\Of\ServiceProvider::class);//must extend the \Ecfectus\Container\ServiceProvider\AbstractServiceProvider class

//psr interface methods

$container->get('id');//returns the instance, or throws a NotFoundException

$container->has('id');//returns bool

//methods specific to this container

//bind a service
$container->bind($id, $callbackOrArray, $share = false);

//share a service (same as above with third flag as true)
$container->share($id, $callbackOrArray);

//$callbackOrArray can be any of the following:

//classname
$container->bind($id, \Some\Class::class);

//instance
$container->bind($id, new \Some\Class());

//callable
$container->bind($id, function($container){
    return new \Some\Class();
});

//an array containing a callable and the required arguments, to save on using reflection (better performance)
$container->bind($id, [function($arg, \Some\Class $instance){
    return $instance->with($arg);
}, 'argument value', \Some\Class::class]);

//allows you to alter the instance before returning it from the container, you must return the instance
$container->extend($id, function($instance, $container){
    return $instance;
});

If using services providers they simply need to provide an array of the services they define, and the register function creating the bindings., (*13)

<?php
use Ecfectus\Container\ServiceProvider\AbstractServiceProvider;

class SomeServiceProvider extends AbstractServiceProvider
{

    protected $provides = [
      someClass::class
    ];

    public function register(){
            /**
             * Or use the shortcuts $this->bind() and $this->share()
             */
        $this->getContainer()->bind(someClass::class, function(){
            return new someClass();
        });
    }

}

Service providers can also implement the BootableServiceProviderInterface and provide a ::boot() method which will get called when the service provider is added via the addServiceProvider function if the container has already been booted, or when the $container->bootServiceProviders(); method is called. This function also has access to the container., (*14)

Notes

There has been a very primitive benchmark done between this as the league container (which is faster than illuminate)., (*15)

It looks positive. Around 20% faster and generally uses less memory (up to 70% less)., (*16)

The reflection container give you complete freedom, but this comes at a cost (can be 2+ times slower), where possible provide the dependency list and register all objects in the container to ensure best performance., (*17)

The Versions

01/10 2016

dev-master

9999999-dev https://github.com/ecfectus/container

Lean PSR11 compatible dependency injection container

  Sources   Download

MIT

The Requires

 

The Development Requires

by Avatar leemason