Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Upon completion of the entire software development process, sometimes need to many people, sometimes also can oneself independently, in either, increased along with the code, as I write this “out of control”, “ugly interface, dirty implementation” gradually, project maintenance costs and difficult to rise, to unsustainable levels, only refactoring or redevelopment.

Primary realm

Hypothetical scenario: We need to write a processing class that can manipulate sessions, databases, and file systems at the same time. We might write it like this.

Boundary characteristics: Operational, but heavily 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();
Copy the code

Disadvantages of writing:

1. Construct objects in public functions. Once it involves changes such as database parameters, it will be a lot of work to modify them

2. The personnel responsible for designing the Writer class should be familiar with various apis of the DB class

Is there a way to reduce coupling?

Second realm (parameter dependence)

Hypothetical scenario: the database address needs to be changed frequently because of different customers. Many classes are called to the 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();
 
Copy the code

While moving the construction of DB classes to the client reduces the workload when it comes to modifying them, a new problem arises: In order to create a Writer class, we need to create the DB class, FileSystem class, etc., which is very demanding for the person responsible for the Writer class. He needs to read many other class documents and create them one by one (and possibly initialize them) before creating the Writer variable he wants.

So, hopefully, there will be a better way for writers to create and call classes with a faster interface, without even having to fill in the parameters.

Third boundary (IOC container)

After the first two areas, we hope to add the following benefits:

$DB =new DB(arg1,arg2) $DB =new DB(arg1,arg2) This kind of statement.

2. Expect objects of type DB to be “global” and can be called at any time during the entire program running.

3. Programmers who call types such as DB do not need to know much about this class and can even create such an object with an alias for a string.

The IOC container can do this by simply treating the IOC container as a global variable and binding the string to the constructor with an associative array.

Let’s start with a container class

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); }}Copy the code

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);
 
});
Copy the code

Container to rely on

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);
Copy the code