Primary dependency Injection and IOC container

Source: Internet
Author: User
Tags closure reflection reflector
Initial wording

When Class A uses Class B, the first is to create a new Class B object within Class A, and then use the.
For example, there is now a controller class that needs to get data from the Repository class. Original wording:

<?php
class repository{public
    function GetData () {return
        "data";
    }
}

Class controller{
    private $repository;
    Public Function __construct () {
        $this->repository = new Repository ();
    }

    Public Function ShowData () {
        $data = $this->repository->getdata ();
        echo $data;
    }
}

$c = new Controller ();
$c->showdata ();
Dependency Injection

Also, Class A uses Class B: Now we create objects of Class B from outside and pass it to Class A.
Now class A does not need to create Class B, just call the B class method.
The following is an example of an injection from a builder:

<?php
class repository{public
    function GetData () {return "data";}
}

Class controller{
    private $repository;
    Public function __construct (Repository $repository) {
        $this->repository = $repository;
    }

    Public Function ShowData () {
        $data = $this->repository->getdata ();
        echo $data;
    }
}

At some other place, instantiate and inject
$repository = new Repository ();
$c = new Controller ($repository);
$c->showdata ();
dependency Inversion

Reference to this document: The dependency reversal criterion is to refer to

dependencies should be interfaces/conventions or abstract classes, not concrete implementations.

Example:

<?php
//first defines an interface to obtain data
interface repositoryinterface{public
    function GetData ();
}

A specific implementation class that obtains data
class Frommysqlrepository implements repositoryinterface{public function from the MySQL database
    getData () {return ' This was
        data from MySQL database ';
    }
}

Class controller{
    private $repository;
    The injected dependency is an interface public
    function __construct (repositoryinterface $repository) {
        $this->repository = $ repository;
    }

    Public Function ShowData () {
        $data = $this->repository->getdata ();
        echo $data;
    }
}

instantiated, injected
$repository = new Frommysqlrepository ();
$c = new Controller ($repository);
$c->showdata ();

One day, you need a different way to get data, such as getting data from the Redis cache. This is the place to modify:

Creating a new class is also implementing the Repositoryinterface interface, but the implementation of the method is to obtain the data from the Redis.
class Fromredisrepository implements repositoryinterface{public
    function GetData () {return ' This is
        data From Redis ';
    }
}

$repository = new Fromredisrepository ()//instantiated place, only need to modify this code
$c = new Controller ($repository);
$c->showdata ();
a junior IOC container.

The above example, all need to manually create dependencies, injection. Create dependencies and injections that can be delivered to the IOC container.
IOC control reversal: i.e.

"The control of creating an object instance is stripped from code control to IOC container control. ”

An example from here: Https://www.insp.top/article/learn-laravel-container. ):

Interface repositoryinterface{Public Function GetData ();}  Class Frommysqlrepository implements repositoryinterface{Public Function GetData () {return ' This is data '
    MySQL database ';  The class Fromredisrepository implements repositoryinterface{Public Function GetData () {return ' This is data
    From Redis ';

    Class controller{private $repository;
    Public function __construct (Repositoryinterface $repository) {$this->repository = $repository;
        The Public Function ShowData () {$data = $this->repository->getdata ();
    echo $data; Echo ' <br> '; }//Manually create dependencies, and inject.
Now to change this approach//$repository = new Frommysqlrepository ();
$repository = new Fromredisrepository ();
$c = new Controller ($repository);

$c->showdata ();

    A primary container class Container {protected $binds;

    protected $instances; Public function bind ($abstract, $concrete) {if ($concrete instanceof Closure) {$this->binds[$abstract] = $concrete;
        else {$this->instances[$abstract] = $concrete;
            ' Public function ' make ($abstract, $parameters = []) {if (Isset ($this->instances[$abstract])) {
        return $this->instances[$abstract];
        } array_unshift ($parameters, $this);
    Return Call_user_func_array ($this->binds[$abstract], $parameters);
}//Create container $container = new container; Add a controller creation script to the container $container->bind (' controller ', function ($container, $moduleName) {return new controller ($c
Ontainer->make ($moduleName));
}); Add a frommysqlrepository creation script to the container $container->bind (' MySQL ', function ($container) {return new frommysqlrepository}
);

Ibid. $container->bind (' Redis ', function ($container) {return new fromredisrepository;});
Created somewhere, called.
$c 1 = $container->make (' controller ', [' MySQL ']); $c 1->showdata ();
Interpretation

The example of this container comes from here: Https://www.insp.top/article/learn-laravel-container.
When I read this example, I looked at it for a while before I understood it. If you've read this, please ignore this "interpretation."
When $container->make (' Controller ', [' MySQL ']), what happened.
1, the first time to enter the container make method:
Array_unshift ($parameters, $this);
Reassembled the $parameters, there are 2 elements: the first is the container, the second is the string ' MySQL '.

Call_user_func_array ($this->binds[$abstract], $parameters);
At this point $this->binds[$abstract] is a controller of the closure that is just bound, namely:

function ($container, $moduleName) {return
    new Controller ($container->make ($moduleName));

2,
Controller this closure calls make again. Make method for the second entry into the container:
Array_unshift ($parameters, $this);
At this time the $parameters is an empty array, reassembled, only one element, that is, the container

Call_user_func_array ($this->binds[$abstract], $parameters);
At this point $this->binds[$abstract] is another closure ' MySQL ', content is

function ($container) {return
    new frommysqlrepository;
};

3, So, $container->make (' controller ', [' MySQL ']); This code
To do 2 things, create a new Frommysqlrepository object first, create a new controller object, and inject it with the new Frommysqlrepository object you created in the previous step. using reflection in the IOC container

The laravel5.5 container is located in vendor\laravel\framework\src\illuminate\container\container.php.
Reflection is used in Larave's IOC container. The main idea is to get the constructor of the object through reflection, to get the constructor parameters, to create dependencies based on the parameters, and then to create the object.
Main code:

The Public Function build ($concrete) {if ($concrete instanceof Closure) {/* ... */} $reflector = new Reflec    Tionclass ($concrete); Gets the reflected object if (! $reflector->isinstantiable ()) {//} $this->buildstack[] = $concrete//Get constructs
    Device $constructor = $reflector->getconstructor (); if (Is_null ($constructor)) {/* ... */} $dependencies = $constructor->getparameters (); Gets the constructor parameter (a set of Reflectionparameter objects) $instances = $this->resolvedependencies ($dependencies);
    Create dependent Array_pop ($this->buildstack); Return $reflector->newinstanceargs ($instances);//Use dependency to create object} protected function Resolvedependencies (array $
    dependencies) {$results = []; foreach ($dependencies as $dependency) {if ($this->hasparameteroverride ($dependency)) {/* ... Dependent if the overridden processing ... */} $results [] = Is_null ($dependency->getclass ())? $this->resolveprimitive ($dependency)//If not an instantiated class, "Bomb OUT with an error ": $this->resolveclass ($dependency);
No problem, use make () to create a dependent instance} return $results; } protected function Resolveclass (Reflectionparameter $parameter) {try {return $this->make ($parameter
    ; GetClass ()->name); The catch (Bindingresolutionexception $e) {/* ...
    Deal with ... * * throw $e;
 }
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.