Parsing PHP Dependency Injection and control inversion

Source: Internet
Author: User
This article mainly introduces the PHP dependency injection (DI) and control inversion (IoC) related data, with a certain reference value, interested in small partners can refer to

First of all rely on injection and control inversion is said to be the same thing, is a design pattern, this design pattern to reduce the coupling between the program, I learned a bit, see TP official website has no relevant articles, write this my book introduce this design mode, hope to contribute some power to TP community.

First of all, do not investigate the definition of the design pattern, otherwise you will be said Foggy, the author is deeply affected by its harm, Baidu has more than n articles, are described from a theoretical point of view, flooded with a lot of jerky words, or Java code description, but also jerky.

Anyway, to figure it out, let's describe the concept of dependency injection in PHP's perspective.

Let's say we have a class here that requires a database connection in the class, and in the most primitive way, we might write this class:


Class Example {    private $_db;  function __construct () {    include "./lib/db.php";    $this->_db = new db ("localhost", "root", "123456", "Test");  function GetList () {    $this->_db->query ("...");//Here the specific SQL statement is omitted  }}

Process:

In the constructor, the database class file include in the first;
The DB class is then instantiated via new DB and incoming database connection information;
The GetList method can then invoke the database class through $this->_db to implement the database operation.

It seems that we have achieved the desired function, but this is the beginning of a nightmare, later example1,example2,example3 .... More and more classes need to use the DB component, if this is the case, if one day the database password changed or DB class changed, would you like to go back to modify all the class files?
OK, in order to solve this problem, the factory pattern appears, we create a factory method, and use the Factory::getdb () method to obtain an instance of the DB component:


Class Factory {public  static function Getdb () {    include "./lib/db.php";    return new Db ("localhost", "root", "123456", "Test");  } }

The sample class becomes:


Class Example {    private $_db;  function __construct () {    $this->_db = Factory::getdb ();  }  function GetList () {    $this->_db->query ("...");//Here the specific SQL statement is omitted  }}

Is that perfect for you? Think again about later example1,example2,example3 .... For all classes, you need to pass FACTORY::GETDB () in the constructor, and in fact you have the coupling of the original direct and DB class to the Factory factory class, the factory class just wraps up the database connection information for you, Although the database information changes as long as the Factory::getdb () method can be modified, but suddenly one day the factory method needs to change the name, or the Getdb method needs renaming, what do you do? Of course, this demand is still very fucked up, but sometimes it does, one solution is:

We do not instantiate the DB component from within the example class, we rely on external injection, what does it mean? Look at the following example:


Class Example {  private $_db;  function GetList () {    $this->_db->query ("...");//Here the specific SQL statement is omitted to write  }  //external injection of the DB connection  function Setdb ($connection) {    $this->_db = $connection;  }}//Call $example = new example (); $example->setdb (Factory: : Getdb ());//Inject DB connection $example->getlist ();

In this way, the example class is completely decoupled from the external class, and you can see that there are no factory methods or DB classes in the DB class. We inject the connection instance directly into it by invoking the Setdb method of the example class from the outside. In this way the example does not care at all how the DB connection was generated.
This is called dependency injection, and instead of creating a dependency within the code, the implementation is passed as a parameter, which makes our program easier to maintain, reduces the coupling of the program code, and implements a loose coupling.

It's not over yet, and we'll assume that the example class uses other external classes in addition to DB, and we pass:


$example->setdb (Factory::getdb ());//Inject DB connection $example->setfile (Factory::getfile ());//inject File processing class $example-> SetImage (Factory::getimage ());//inject image processing class ...

We've been writing so many sets for so long? Tired or tired?
OK, in order not to write so many lines of code each time, we went to get a factory method:


Class Factory {public  static function Getexample () {    $example = new Example ();    $example->setdb (Factory::getdb ());//inject DB connection    $example->setfile (Factory::getfile ());//inject File processing class    $ Example->setimage (Factory::getimage ());//inject image processing class    return $expample;  }}

When instantiating example, it becomes:


$example =factory::getexample (); $example->getlist ();

It seems perfect, but how does it feel to go back to the scene when I first used the factory method? This is really not a good solution, so a concept is proposed: containers, also called IOC containers, di containers.

We originally injected various classes through the Setxxx method, the code is very long, a lot of methods, although it can be packaged through a factory method, but not so cool, well, we do not have to setxxx method, so also do not have to factory method two times packaging, then we also how to achieve dependency injection?
Here we introduce a convention: in the constructor of the example class, pass in a parameter named Di $di, as follows:


Class Example {  private $_di;  function __construct (Di & $di) {    $this->_di = $di;  }  Get DB instance  function GetList () {    $this->_di->get (' db ')->query ("...") through the DI container;//Here the specific SQL statement is omitted.  } } $di = new Di (), $di->set ("db", function () {  return new db ("localhost", "root", "root", "test");  }); $example = new Example ($DI); $example->getlist ();

DI is the IOC container, the so-called container is to store the various classes we may use, we set a instance named DB by $di->set (), because it is passed through the callback function, so the set does not immediately instantiate the DB class, but when the $di-> Get (' db ') is instantiated, similarly, when designing the Di class, you can also incorporate a singleton pattern.

So we just declare a DI class at the global scope, put all the classes that need to be injected into the container, and then pass the container as a constructor parameter to example, and get the instance from the container in the example class. Of course, it is not necessarily a constructor, you can also use a setdi (di $di) method to pass in the Di container, in short, the agreement is you make, you know the line.

This relies on injection and the key container concept has been introduced, and the rest is to use and understand it in practice!

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.