php - What is a Dependency Injection Container? -


i trying understand role of dependency injection container because strikes me fundamental in maintainable code.

as understand it, dic title suggests: container dependencies collected together. instead of seeing new foo\bar on application, new instances generated inside of container , passed through each other needed (e.g., model instantiated instance of database, instantiated instance of config).

i have attempted make very simple dic. result.

in front controller instantiating new app\core\container.

my container looks this:

<?php  namespace app\core;  use app\config;  class container {     public $config;     public $router;     public $database;      public $model;     public $view;     public $controller;      public function __construct()     {         $this->config   = new config;         $this->router   = new router;         $this->database = new database($this->config);     }      public function add()     {         // add dependencies outside?     }      public function getinstance(/* string */)     {         // return instance use somewhere?     }      public function newmodel($model)     {         $model = $this->getmodelnamespace() . $model;         $this->model = new $model($this->database);         return $this->model;     }      private function getmodelnamespace()     {         $namespace = 'app\models\\';         if (array_key_exists('namespace', $this->params = [])) {             $namespace .= $this->params['namespace'] . '\\';         }         return $namespace;     }      public function newview($params)     {         $this->view = new view($this->model, $params);         return $this->view;     }      public function newcontroller($controller)     {         $controller = $this->getcontrollernamespace() . $controller;         $this->controller = new $controller;         return $this->controller;     }      private function getcontrollernamespace()     {         $namespace = 'app\controllers\\';         if (array_key_exists('namespace', $this->params = [])) {             $namespace .= $this->params['namespace'] . '\\';         }         return $namespace;     } } 

questions

  • could implementation above, although simple, classed basic dependency injector?
  • is dependency injection container comprised of 1 class?

note: first 3 headings answer questions, while following ones answer anticipated questions , provide coverage of in first 2 sections.

could classified dependency injection container?

no, not dependency injection container. dependency injection container meant reduce work instantiation requires determining, creating, , injecting dependencies. rather have there appears combination of factory , service locator.

factories abstract creation of objects. container class doing. calling designated methods (i.e., newmodel), container takes on responsibility of locating exact object instantiated , constructing instance of object.

the reason call "poor" factory it's beginning might used locate services. service locators work hiding object's dependencies: instead of being dependent on genericservice, object might depend on service locator. given service locator, can request instance of genericservice. see similar behavior beginning take hold in add() , getinstance() methods. service locators considered anti-patterns because abstract dependencies therefore making code impossible test!

is dependency injection container comprised of 1 class?

it depends. make simple dependency injection container 1 class. issue nature of simple container tends more advanced not-so-simple container. when start improving pattern, need consider how different components play together. ask yourself: follow solid principles? if not, refactoring necessary.

what dependency injection container?

i said above, again: dependency injection container meant reduce work instantiation requires determining, creating, , injecting dependencies. dic @ dependencies of class, , dependencies dependencies may have, , on... in sense, container responsible hierarchically instantiating dependencies.

the container class provide relies on strict definitions of pre-defined classes. example, classes in model layer appear only dependent on database connection. (similar statements can said classes in controller & view layer).

how dependency injection container find dependencies?

a dependency injection container detect dependencies. typically happens through 1 of 3 mechanisms: autowiring, annotations, , definitions. php-di docs provide idea of 3 of these entail here. in short, though: autowiring detects dependencies reflecting on class, annotations used write in dependencies using comments above class, , definitions used hard-code dependencies. personally, prefer autowiring because it's clean & simple.

can create simple dependency injection container or no?

yes, can. start idea injector should able instantiate object (service, view, controller, etc...). needs @ relevant object , hierarchically instantiate dependencies (hint: possibly through method of recursion).

a quick example of simple injector using autowiring looks this:

<?php class injector {     public function make($classname)     {         $dependencies = [];          //create reflection of class-to-make's constructor dependencies         $classreflection = new reflectionmethod($classname, "__construct");          foreach($classreflection->getparameters() $parameter) {             $dependencyname = $parameter->getclass()->getname();              //use injector make instance of dependency             $dependencies[] = $this->make($dependencyname);         }          $class = new reflectionclass($classname);          //instantiate class dependencies         return $class->newinstanceargs($dependencies);     } } 

tested following, can see how injector recursively checks , instantiates dependencies

class {     protected $b;     public function __construct(b $b) { $this->b = $b; }     public function output(){ $this->b->foo(); } }  class b {     protected $c;     public function __construct(c $c) { $this->c = $c; }     public function foo() { $this->c->bar(); } }  class c {     public function __construct() { }     public function bar() { echo "world!"; } }  $injector = new injector;  $a = $injector->make("a"); //no need manually instantiate a's dependency, b, or b's dependency, c  $a->output(); 

this basic injector has obvious faults. example, there opportunity create recursion disaster if 2 classes dependent on each other (there should check that). however, is, works basic example of injector looks like.

injector vs. dependency injection container

to make more powerful , fall under definition of "dependency injection container", you'd want way share instantiated instances across multiple make() calls. example, may have method called share(). method store instance passed it. whenever class built through make() method , depends on class shared, instead of instantiating new instance, use already-instantiated one.

for simple & powerful dependency injection container suggest auryn, means, try understand & create own before using ones available.


Comments