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
Post a Comment