Dependency inversion principle of PHP five object oriented principles of DIP detailed explanation

  • 2021-09-20 19:44:38
  • OfStack

In this paper, the dependency inversion principle (DIP), one of the five object-oriented principles of PHP, is described with examples. Share it for your reference, as follows:

What is dependency inversion? Simply put, it is to invert dependencies into dependent interfaces. The specific concepts are as follows:

1. The upper level module should not depend on the lower level module, they all depend on an abstraction (the parent class cannot depend on the subclass, they all depend on the abstract class)

2. Abstraction cannot depend on concreteness, but concreteness should depend on abstraction.

Note that the interface here is not a narrow interface.

Why rely on interfaces? Because interfaces embody abstractions of problems, and because abstractions are generally relatively stable or relatively infrequent, concreteness is changeable. Dependency abstraction is therefore the basis for implementing code extension and runtime binding (polymorphism): Any subclass of the abstract class that is implemented can be used by the class. Here, emphasize the concept of extensibility. Usually extensibility refers to the extension of known behavior. When talking about interfaces, it is also mentioned that interfaces should be relative. This tells us that no matter how advanced the design pattern is, we can't achieve the immutable ground without modifying the code. Of these five principles of object-oriented, I think dependency inversion is the most difficult to understand and implement.

Take the employee class as an example


<?php
interface employee
{
  public function working();
}
class teacher implements employee
{
  public function working()
  {
    echo 'teaching...';
  }
}
class coder implements employee
{
  public function working()
  {
    echo 'coding...';
  }
}
class workA
{
  public function work()
  {
    $teacher = new teacher();
    $teacher->working();
  }
}
class workB
{
  private $e;
  public function set(employee $e)
  {
    $this->e = $e;
  }
  public function work()
  {
    $this->e->working();
  }
}
$worka = new workA;
$worka->work();
$workb = new workB;
$workb->set(new teacher());
$workb->work();

In workA, the work method depends on the teacher implementation; In workB, work relies instead on abstraction, so that the desired objects can be passed in as parameters. The above code realizes a certain degree of decoupling through interface, but it is still limited. Not only using interfaces, but also using factories can achieve a certain degree of decoupling and dependency inversion.

In workB, the teacher instance is passed in through the set method, thus implementing the factory pattern. Since this implementation is still hard-coded, in order to realize the further expansion of the code, this dependency is written in the configuration file, indicating that workB needs an teacher object, which is specifically configured by a program whether it is correct (such as whether the dependent class file exists) and the implementation that is dependent in the loading configuration. This detection program is called IOC container.

The concept of IOC (Inversion of Control) has been seen in many articles. In fact, IOC is synonymous with the principle of relying on inversion (Dependence Inversion Principle, DIP). When you mention IOC, you may also see someone mention concepts such as DI. DI, that is, dependency injection, is generally considered that dependency injection (DI) and dependency lookup (DS) are two implementations of IOC. However, with the evolution of some generalities, the relationship between these concepts has become very blurred, and some people think that IOC is DI. Some people think that the description of dependency injection is more appropriate than IOC, and the relationship between these concepts is not entangled here.

In the classic J2EE design, DAO layer and Servicen layer are usually subdivided into interface layer and implementation layer, and then the dependencies are configured in the configuration file, which is the most common application of DIP. Spring framework is a good IOC container, which strips the control right from the code to IOC window, which is realized by XML configuration file. Spring establishes the dependency relationship between objects according to the configuration file during execution.

As shown in the following code


<bean scopre="prototype" class="cn.notebook.action.NotebookListOtherAction" id="notebookListOtherAction">
  <property ref="userReplyService" name="userReplyService" />
  <property ref="userService" name="userService" />
  <property ref="permissionService" name="permissionService" />
  <property ref="friendService" name="friendService" />
</bean>

However, there is a problem with this setting 1, and the configuration file will become larger and larger, and the relationship between them will become more and more complicated. It can't escape the nightmare of constantly modifying the code with the change of application and business (the configuration file is considered as part 1 of the code here. And in actual development, it is rare to simply modify the configuration file. If the general configuration file is modified, the code will be modified accordingly)

In PHP, there is also a similar implementation imitating Spring, that is, the dependency is written in the configuration file, and the required objects are generated through the configuration file. I think this kind of code is still implemented for the sake of implementation. In Srping, the configuration file configures not only the runtime dependencies of a class, but also transaction management, AOP, delayed loading and so on. The consumption of PHP to realize the above features is huge. Linguistically speaking, PHP, a dynamic scripting language, is different from compiled languages in implementing some polymorphic features. Secondly, PHP, as an agile development language, emphasizes rapid development, clear logic and easier code to understand. If the framework of various design patterns is attached, it is not desirable in terms of technical implementation and operational efficiency. The core principle of dependency inversion is decoupling. If we break away from this most primitive principle, we will put the cart before the horse.

In fact, many design patterns have implied the principle of dependency inversion, and we are also doing some work of dependency inversion intentionally or unintentionally. Just as PHP, there is no perfect IOC container at present, and perhaps PHP is not needed at all.

If DIP is met:

1. Each higher-level class proposes an interface declaration for the service it needs, and the lower-level class implementation implements this interface.

2. Each high-level class consumes the service through this abstract interface.

For more readers interested in PHP related content, please check the topics on this site: "Introduction to php Object-Oriented Programming", "Encyclopedia of PHP Array (Array) Operation Skills", "Introduction to PHP Basic Syntax", "Summary of PHP Operation and Operator Usage", "Summary of php String (string) Usage", "Introduction to php+mysql Database Operation" and "Summary of php Common Database Operation Skills"

I hope this paper is helpful to everyone's PHP programming.


Related articles: