PHP dependency injection (DI) and control inversion (IoC) details, diioc

Source: Internet
Author: User

PHP dependency injection (DI) and control inversion (IoC) details, diioc

First, dependency injection and control reversal refer to the same thing. They are a design pattern used to reduce the coupling between programs, check that there are no related articles on the TP official website. Write down this article to introduce this design mode and hope to contribute some strength to the TP community.

First of all, do not look into the definition of this design model. Otherwise, you will be confused by the cloud. The author is suffering from it. Baidu has more than N articles, all of which are described from a theoretical perspective, it is filled with a lot of raw words, either described in java code, or lost.

In any case, I finally figured it out. The following describes the concept of dependency injection from the php perspective.

Let's assume that we have a class that requires database connection in the class. According to the most primitive method, we may write this class as follows:

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 will be omitted and not written }}

Process:

Include the database files in the constructor first;
Then, the database class is instantiated through new Db and the database connection information is passed in;
Then, the getList method can call the database class through $ this-> _ db to implement database operations.

It seems that we have implemented the desired function, but this is the beginning of a nightmare. In the future, example1, example2, example3 .... more and more classes need to use the db Component. If the Database Password is changed or the database class changes one day, wouldn't we have to modify all class files?
OK. To solve this problem, the Factory mode has emerged. We created a Factory method and obtained the db Component instance through the Factory: getDb () method:

class Factory {  public static function getDb(){    include "./Lib/Db.php";    return new Db("localhost","root","123456","test");  } }

Sample class changed:

Class example {private $ _ db; function _ construct () {$ this-> _ db = Factory: getDb ();} function getList () {$ this-> _ db-> query ("...... "); // here the specific SQL statement will be omitted and not written }}

Is this perfect? Think about example1, example2, example3 .... for all classes, you must use Factory: getDb (); In the constructor to obtain a Db instance, in fact, you have changed from the original direct coupling with the Db class to the coupling with the Factory class. The Factory class just helps you pack the database connection information, even if the database information changes, you only need to modify the Factory: getDb () method, but one day the Factory method needs to be renamed, or the getDb method needs to be renamed. What should you do? Of course, this kind of requirement is still very tricky, but sometimes it does exist. One solution is:

We don't instantiate the Db Component from inside the example class. We rely on external injection. What do we mean? See the following example:

Class example {private $ _ db; function getList () {$ this-> _ db-> query ("...... "); // The specific SQL statement is omitted here.} // The function setDb ($ connection) {$ this-> _ db = $ connection;} is injected from the external database ;}} // 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. You can see that there are no factory methods or Db classes in the Db class. We call the setDb method of the example Class from the outside to inject the connected instance directly. In this way, example does not have to worry about how db connections are generated.
This is called dependency injection. The implementation does not create dependencies in the code, but transmits them as a parameter, which makes our program easier to maintain and reduces the coupling of program code, implements a loose coupling.

This is not complete yet. Let's assume that in the example class, other external classes are used in addition to db, and we use:

$ Example-> setDb (Factory: getDb (); // inject db connection $ example-> setFile (Factory: getFile ()); // inject File Processing class $ example-> setImage (Factory: getImage (); // inject Image processing class...

Are we constantly writing so many sets? Tired?
OK. In order not to write so many lines of code each time, we have another factory method:

Class Factory {public static function getExample () {$ example = new example (); $ example-> setDb (Factory: getDb ()); // inject db connection $ example-> setFile (Factory: getFile (); // injection File Processing class $ example-> setImage (Factory: getImage ()); // inject the Image processing class return $ expample ;}}

Changed:

$example=Factory::getExample();$example->getList();

It seems perfect, but how does it feel like it is back to the scenario where the first factory method was used? This is indeed not a good solution, so we propose another concept: container, also called IoC container and DI container.

We used to inject various types through the setXXX method. The code is very long and there are many methods. Although we can use a factory method for packaging, it is not so cool. Well, we don't need to use the setXXX method, so we don't need to use the factory method for secondary packaging. How can we implement dependency injection?
Here we introduce a convention: input a parameter named Di $ di In the constructor of the example class, as shown below:

Class example {private $ _ di; function _ construct (Di & $ di) {$ this-> _ di = $ di ;} // obtain the function getList () {$ this-> _ di-> get ('db')-> query ("...... "); // here the specific SQL statement will be omitted and not written} $ 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 types of instances we may use, we set an instance named db through $ di-> set, because it is passed in through the callback function, the db class will not be instantiated immediately during set, but will be instantiated only when $ di-> get ('db, similarly, you can also integrate the singleton mode when designing di classes.

In this way, we only need to declare a Di class in the global scope, put all the classes to be injected into the container, and then pass the container as a constructor parameter to example, you can 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 import the Di container. In short, the conventions are set by you. You just need to know it yourself.

In this way, dependency injection and key container concepts have 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.