How PHP programmers understand dependency injection containers (Dependency injection container)
Background Knowledge
The traditional idea is that the application uses an Foo class, the Foo class is created and the method of the Foo class is called, and if a bar class is needed within the method, the bar class is created and the bar class is called, and the method requires a BIM class, creates the Bim class, and does some other work.
<?php
Code "1"
Class Bim
{
Public Function dosomething ()
{
echo __method__, ' | ';
}
}
Class Bar
{
Public Function dosomething ()
{
$bim = new Bim ();
$bim->dosomething ();
echo __method__, ' | ';
}
}
Class Foo
{
Public Function dosomething ()
{
$bar = new Bar ();
$bar->dosomething ();
Echo __method__;
}
}
$foo = new Foo ();
$foo->dosomething (); Bim::d osomething| Bar::d osomething| Foo::d osomething
The idea of using dependency injection is that the application uses the Foo class, the Foo class needs the bar class, the bar class needs the Bim class, then creates the Bim class, creates the bar class and injects the BIM, creates the Foo class, injects the bar class, calls the Foo method, and Foo calls the Bar method. Then do some other work.
<?php
Code "2"
Class Bim
{
Public Function dosomething ()
{
echo __method__, ' | ';
}
}
Class Bar
{
Private $bim;
Public function __construct (Bim $bim)
{
$this->bim = $bim;
}
Public Function dosomething ()
{
$this->bim->dosomething ();
echo __method__, ' | ';
}
}
Class Foo
{
Private $bar;
Public function __construct (Bar $bar)
{
$this->bar = $bar;
}
Public Function dosomething ()
{
$this->bar->dosomething ();
Echo __method__;
}
}
$foo = new Foo (new Bim ());
$foo->dosomething (); Bim::d osomething| Bar::d osomething| Foo::d osomething
This is the control reversal mode. The control of the dependency is reversed to the starting point of the call chain. This allows you to fully control the dependencies, by adjusting the different injection objects to control the behavior of the program. For example, the Foo class uses Memcache, and you can switch to Redis without modifying the Foo class code.
The idea behind using a dependency injection container is that the application needs to go to the Foo class, the Foo class is obtained from the container, the container creates the Bim class, creates the bar class and injects the BIM, creates the Foo class, injects the bar, the application calls the Foo method, Foo calls the Bar method, and then does some other work.
In short, the container is responsible for instantiating, injecting dependencies, handling dependencies, and so on.
Code Demo Dependency Injection container (Dependency injection container)
The simplest container class to explain, this code from the Twittee
<?php
Class Container
{
Private $s = array ();
function __set ($k, $c)
{
$this->s[$k] = $c;
}
function __get ($k)
{
return $this->s[$k] ($this);
}
}
This code uses a magic method that __set () is invoked when assigning a value to an inaccessible property. __get () is invoked when the value of an inaccessible property is read.
<?php
$c = new Container ();
$c->bim = function () {
return new Bim ();
};
$c->bar = function ($c) {
Return to New Bar ($c->bim);
};
$c->foo = function ($c) {
return new Foo ($c->bar);
};
Get Foo from container
$foo = $c->foo;
$foo->dosomething (); Bim::d osomething| Bar::d osomething| Foo::d osomething
This code uses an anonymous function
Here's a little bit of code to demonstrate that the container code comes from simple di container
<?php
Class IoC
{
protected static $registry = [];
public static function bind ($name, callable $resolver)
{
Static:: $registry [$name] = $resolver;
}
public static function make ($name)
{
if (Isset (static:: $registry [$name])) {
$resolver = static:: $registry [$name];
return $resolver ();
}
throw new Exception (' Alias does not exist in the IoC registry. ');
}
}
Ioc::bind (' Bim ', function () {
return new Bim ();
});
Ioc::bind (' Bar ', function () {
Return to New Bar (Ioc::make (' Bim '));
});
Ioc::bind (' foo ', function () {
return new Foo (Ioc::make (' Bar '));
});
Get Foo from container
$foo = Ioc::make (' foo ');
$foo->dosomething (); Bim::d osomething| Bar::d osomething| Foo::d osomething
This code uses a late-static binding
Dependency Injection Container (Dependency injection container) Advanced features
The real Dependency injection container will provide more features, such as
Automatic binding (autowiring) or automatic parsing (Automatic resolution)
annotation parser (annotations)
Deferred injection (Lazy injection)
The following code implements the autowiring on the basis of twittee.
<?php
Class Bim
{
Public Function dosomething ()
{
echo __method__, ' | ';
}
}
Class Bar
{
Private $bim;
Public function __construct (Bim $bim)
{
$this->bim = $bim;
}
Public Function dosomething ()
{
$this->bim->dosomething ();
echo __method__, ' | ';
}
}
Class Foo
{
Private $bar;
Public function __construct (Bar $bar)
{
$this->bar = $bar;
}
Public Function dosomething ()
{
$this->bar->dosomething ();
Echo __method__;
}
}
Class Container
{
Private $s = array ();
Public Function __set ($k, $c)
{
$this->s[$k] = $c;
}
Public Function __get ($k)
{
return $this->s[$k] ($this);
return $this->build ($this->s[$k]);
}
/**
* Automatic binding (autowiring) automatic parsing (Automatic resolution)
*
* @param string $className
* @return Object
* @throws Exception
*/
Public function Build ($className)
{
If it is an anonymous function (Anonymous functions), also called a closure function (closures)
if ($className instanceof Closure) {
Execute the closure function and the result
Return $className ($this);
}
/** @var Reflectionclass $reflector * *
$reflector = new Reflectionclass ($className);
Check that the class is instantiated, excluding abstract class abstract and object interface interface
if (! $reflector->isinstantiable ()) {
throw new Exception ("Can ' t instantiate this.");
}
/** @var Reflectionmethod $constructor Get the constructor of the class.
$constructor = $reflector->getconstructor ();
If no constructor, directly instantiate and return
if (Is_null ($constructor)) {
return new $className;
}
Takes the constructor argument and returns the argument list by Reflectionparameter array
$parameters = $constructor->getparameters ();
Recursive resolution of parameters of constructors
$dependencies = $this->getdependencies ($parameters);
Creates a new instance of a class, and the arguments given are passed to the constructor of the class.
Return $reflector->newinstanceargs ($dependencies);
}
/**
* @param array $parameters
* @return Array
* @throws Exception
*/
Public Function getdependencies ($parameters)
{
$dependencies = [];
/** @var Reflectionparameter $parameter * *
foreach ($parameters as $parameter) {
/** @var Reflectionclass $dependency * *
$dependency = $parameter->getclass ();
if (Is_null ($dependency)) {
is a variable and has a default value to set the default value
$dependencies [] = $this->resolvenonclass ($parameter);
} else {
is a class, recursive parsing
$dependencies [] = $this->build ($dependency->name);
}
}
return $dependencies;
}
/**
* @param reflectionparameter $parameter
* @return Mixed
* @throws Exception
*/
Public Function Resolvenonclass ($parameter)
{
Default values are returned with default values
if ($parameter->isdefaultvalueavailable ()) {
return $parameter->getdefaultvalue ();
}
throw new Exception (' I have no idea what ');
}
}
// ----
$c = new Container ();
$c->bar = ' bar ';
$c->foo = function ($c) {
return new Foo ($c->bar);
};
Get Foo from container
$foo = $c->foo;
$foo->dosomething (); Bim::d osomething| Bar::d osomething| Foo::d osomething
// ----
$di = new Container ();
$di->foo = ' foo ';
/** @var Foo $foo * *
$foo = $di->foo;
Var_dump ($foo);
/*
FOO#10 (1) {
Private $bar =>
Class Bar#14 (1) {
Private $bim =>
Class Bim#16 (0) {
}
}
}
*/
$foo->dosomething (); Bim::d osomething| Bar::d osomething| Foo::d osomething
The principles of the above code refer to the official PHP Documentation: Reflection, PHP 5 has a full reflection API, adding the ability to reverse engineer classes, interfaces, functions, methods, and extensions. In addition, the reflection API provides a way to remove documentation comments from functions, classes, and methods.