Analysis of PHP dependency injection container knowledge points

Time:2021-9-15

Dependency injection container understanding

coupling

A good code structure design must be loosely coupled, which is also the purpose of many general design patterns. It is to gather the code of the same function scattered everywhere to form a module, and then communicate between different modules through some small and clear channels.

In practice, the interdependence between different functions and modules is inevitable, and how to deal with the relationship between these dependencies is the key to whether the code structure can become better.

<?php

class User

{

  public function register($user)

  {

    //Registration operation

    ...

 

    //Send confirmation email

    $notify = new Notify();

    $notify->sendEmail('register', $user);

  }

}

 

class Notify

{

  public function sendEmail($type, $data)

  {

    switch $type {

      case 'register':

        //Send registration confirmation email

        $email = new Email($type);

        $email->send($data);

      ...

    }

  }

}

 

class Email

{

  public function send($data)

  {

    //Send mail

  }

}

In the above code, the three classes depend on each other layer by layer. The order of instantiation of the three classes is user – > notify – > email

In other words, I instantiate the user class first. Maybe I execute some code before I instantiate other classes I need, such as notify, and so on.

This dependency makes us have to do some preparatory work to get the required dependency. Sometimes a new operation may not be enough. This part of work is called coupling, which will make an independent function class have to care about some operations that have nothing to do with its own main function.

Remove the dependency of one class on other classes

To solve this problem, I can first instantiate the email class, then instantiate notify, then pass the email object as a parameter to notify, finally instantiate the user class, and then pass notify in. This is called dependency injection. You can see that the order of class instantiation in this process is completely reversed. Instantiate the dependent object first rather than the final required object first. This is the inversion of control.

The code is as follows:


<?php

$email = new Email();

$notify = new Notify($email);

$user = new User($notify);

You can inject the required dependencies through the constructor, or you can use some other methods.

Hosting dependencies with containers

There are new problems. Only three classes in the example are OK. If the user class relies on notify to send e-mail, model to save the database, and redis to cache, although the dependency is transferred to the outside of the class, it will still lead to a lot of manual preparations when I just want to instantiate the user, which will confuse the code. So a container is needed at this time. The purpose of this container is to manage these dependencies for me.

<?php

//Container

class Container implements ArrayAccess

{

  protected $values = [];

 

  public function offsetGet($offset) 

  {

    return $this->values[$offset]($this);

  }

 

  public function offsetSet($offset, $value) 

  {

    $this->values[$offset] = $value;

  }

}

When the program starts, we can uniformly register a series of basic services in one place.


<?php

$container = new Container();

 

$container['notify'] = function($c) {

  return new Notify();

};

 

$container['email'] = function($c) {

  return new Email();

};

This will happen

<?php

class User

{

  public function register($user)

  {

    //Registration operation

    ...

 

    //Send confirmation email

    $container('notify')->sendEmail('register', $user);

  }

}

 

class Notify

{

  public function sendEmail($type, $data)

  {

    switch $type {

      case 'register':

        //Send registration confirmation email

        $email = $container['email'];

        $email->send($data);

      ...

    }

  }

}

 

class Email

{

  public function send($data)

  {

    //Send mail

  }

}

That is, when the user needs notify, he will ask the container for the objects of this class. I don’t care what other things notify depends on, because notify will also ask the container for its own dependencies. The processing of all these dependencies is completely hosted to the container. We neither need to care about the hierarchical relationship between dependencies, nor avoid the coupling between dependencies.

It should be noted that the dependency injection container generally only accepts an anonymous function rather than an instantiated object. The anonymous function will tell the container how to obtain an object, so that a service can be instantiated when needed

The above is all the relevant knowledge points introduced this time. Thank you for your learning and support for developeppaer.

Recommended Today

Beautify your code VB (VBS) code formatting implementation code

However, vb.net does have many new functions that VB6 does not have. The automatic typesetting of code is one, which is the function we want to realize today – VB code formatting.Let’s look at the effect: Before formatting: Copy codeThe code is as follows: For i = 0 To WebBrowser1.Document.All.length – 1 If WebBrowser1.Document.All(i).tagName = […]