SoFunction
Updated on 2025-02-28

The triple realm of PHP decoupling (A brief discussion on service containers)

Before reading this article, you need to master: PHP syntax, object-oriented

In the process of completing the entire software project development, sometimes multiple people need to cooperate, and sometimes they can also complete it independently. No matter which one, as the code volume increases, it will "out of control" as it is written, gradually "ugly interfaces and dirty implementations". The cost and difficulty of project maintenance have increased, and it has reached a difficult level, and there is only refactoring or redevelopment.

The first level

Suppose scenario: We need to write a processing class that can operate sessions, databases, and file systems at the same time. We might write that.

Realm characteristics: Can operate, but severely coupled

class DB{
 public function DB($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class FileSystem{
 public function FileSystem($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class Session{
 public function Session($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class Writer{
 public function Write(){
 $db=new DB(1,2);
 $filesystem=new FileSystem(3,4);
 $session=new Session(5,6);
 }
}
$writer=new Writer();
$writer->write();

Disadvantages of writing:

1. Construct objects in public functions. Once changes such as database parameters are involved, modification will be done a lot.

2. The person responsible for designing the Writer class needs to be familiar with various APIs such as DB.

Is there a way to reduce the coupling?

The second level of realm (parameter dependency)

Suppose scenario: The database address needs to be changed frequently because of different customers. There are many classes called to DB (if there are dozens). I hope that even if the database address is changed, there is no need to modify the code of these classes.

class DB{
 public function DB($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class FileSystem{
 public function FileSystem($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class Session{
 public function Session($arg1,$arg2){
 echo 'constructed!'.PHP_EOL;
 }
}
class Writer{
 protected $_db;
 protected $_filesystem;
 protected $_session;
 public function Set($db,$filesystem,$session){
 $this->_db=$db;
 $this->_filesystem=$filesystem;
 $this->_session=$session;
 }
 public function Write(){

 }
}
$db=new DB(1,2);
$filesystem=new FileSystem(3,4);
$session=new Session(5,6);
$writer=new Writer();
$writer->Set($db,$filesystem,$session);
$writer->write();

Although the construction of the DB class is moved to the client, once modification is involved, the workload is greatly reduced, a new problem is: in order to create a Writer class, we need to create DB classes, FileSystem classes, etc., which is very demanding for those responsible for the Writer class. They need to read a lot of other class documents, create one by one (maybe initialized) before they can create the writer variables they want.

Therefore, we hope that there can be a better way of writing so that people who write Writer classes can create and call the classes they want with a faster interface, without even filling in parameters.

The third level of realm (IOC container)

After the first two levels of realms, we hope to add the following benefits:

1. I hope that the DB class, Session class, and FileSystem class are "used as soon as possible" without cumbersome initialization every time, such as writing statements such as $db=new DB(arg1,arg2);

2. I hope that objects of DB and other types are "global" and can be called at any time during the entire program run.

3. Programmers who call DB and other types do not need to know too many details of this class, and can even create such an object with a string alias.

The one that can achieve the above goal is the IOC container. You can simply regard the IOC container as a global variable and bind the string to the constructor with the associative array.

Let's implement a container class first

class Container{
 public $bindings;
 public function bind($abstract,$concrete){
 $this->bindings[$abstract]=$concrete;
 }
 public function make($abstract,$parameters=[]){
 return call_user_func_array($this->bindings[$abstract],$parameters);
 }
}

Service registration (binding)

$container=new Container();
$container->bind('db',function($arg1,$arg2){
 return new DB($arg1,$arg2);
});
$container->bind('session',function($arg1,$arg2){
 return new Session($arg1,$arg2);
});
$container->bind('fs',function($arg1,$arg2){
 return new FileSystem($arg1,$arg2);
});

Container dependencies

class Writer{
 protected $_db;
 protected $_filesystem;
 protected $_session;
 protected $container;
 public function Writer(Container $container){
 $this->_db=$container->make('db',[1,2]);
 $this->_filesystem=$container->make('session',[3,4]);
 $this->_session=$container->make('fs',[5,6]);
 }
}
$writer=new Writer($container);

The above is all the content of this article. I hope that the content of this article will help you study or work. I also hope to support me more!