当前位置:首页 > PHP教程 > php高级应用 > 列表

控制反转原则,它和依赖注入有什么联系

发布:smiling 来源: PHP粉丝网  添加日期:2022-07-23 09:54:47 浏览: 评论:0 

控制反转(IOC)

首先,我们来看一个例子。

  1. class Person 
  2.  
  3. { 
  4.  
  5.    private $name = ''; 
  6.  
  7.    private $age = 0; 
  8.  
  9.  
  10.  
  11.    public function __construct(string $name, int $age) 
  12.  
  13.    { 
  14.  
  15.        $this->name = $name; 
  16.  
  17.        $this->age = $age; 
  18.  
  19.    } 
  20.  
  21.  
  22.  
  23.    public function eat () 
  24.  
  25.    { 
  26.  
  27.        echo '吃东西' . PHP_EOL; 
  28.  
  29.    } 
  30.  
  31.  
  32.  
  33.    public function drink () 
  34.  
  35.    { 
  36.  
  37.        echo '喝水' . PHP_EOL; 
  38.  
  39.    } 
  40.  
  41.  
  42.  
  43.    public function sleep () 
  44.  
  45.    { 
  46.  
  47.        echo '睡觉' . PHP_EOL; 
  48.  
  49.    } 
  50.  
  51.  
  52.  
  53.    public function wakeup () 
  54.  
  55.    { 
  56.  
  57.        echo '起床' . PHP_EOL; 
  58.  
  59.    } 
  60.  
  61.  
  62.  
  63.    public function drive () 
  64.  
  65.    { 
  66.  
  67.        echo '开车' . PHP_EOL; 
  68.  
  69.    } 
  70.  
  71.  
  72.  
  73.    public function wash () 
  74.  
  75.    { 
  76.  
  77.        echo '洗漱' . PHP_EOL; 
  78.  
  79.    } 
  80.  
  81. } 

小明现在早上起来需要去上班,那么小明需要做以下事情

  1. $person = new Person('小明', 24); 
  2.  
  3. $person->wakeup(); 
  4.  
  5. $person->wash(); 
  6.  
  7. $person->eat(); 
  8.  
  9. echo '带上车钥匙、手机、电脑' .PHP_EOL; 
  10.  
  11. $person->drive(); 

上面的流程都是由程序员自己控制的。现在,我们想办法,让框架来控制流程。我们在Person类中新增一个方法,代码如下:

  1. public function work (callable $bring) 
  2.  
  3. { 
  4.  
  5.     $this->wakeup(); 
  6.  
  7.     $this->wash(); 
  8.  
  9.     $this->eat(); 
  10.  
  11.     $bring(); 
  12.  
  13.     $this->drive(); 
  14.  
  15. } 

小黄也需要去上班,现在他只安装框架的指导就可以完成上班的动作了。

  1. $person = new Person('小黄', 29); 
  2.  
  3. $person->work(function () 
  4.  
  5. { 
  6.  
  7.     echo '带上手机、车钥匙、文件' . PHP_EOL; 
  8.  
  9. }); 

修改后的代码完成了控制反转,以前的代码整个上班的流程由程序员控制,修改后的是由框架控制上班的流程的。程序的流程控制由程序员“反转”到了框架。

现在可以给出控制反转的定义了:

实际上,控制反转是一个比较笼统的设计思想,并不是一种具体的实现方法,一般用来指导框架层面的设计。这里所说的“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。

依赖注入

控制反转是一种设计思想,而依赖注入是一种具体的编码技巧,依赖注入是实现控制反转最常用的技巧。依赖注入看起来“高大上”,实际上非常容易理解和掌握。

那到底什么是依赖注入呢?我们用一句话来概括就是:不通过 new() 的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类使用。

下面来看一个实例:

  1. interface Log 
  2.  
  3. { 
  4.  
  5.    function write (string $msg); 
  6.  
  7. } 
  8.  
  9.  
  10.  
  11. class TextLog implements Log 
  12.  
  13. { 
  14.  
  15.    public function __construct($dirname, $txtname) 
  16.  
  17.    { 
  18.  
  19.        $this->makeDir($dirname); 
  20.  
  21.        $this->mkTxt($txtname); 
  22.  
  23.    } 
  24.  
  25.  
  26.  
  27.    private function makeDir (string $dirName) :void 
  28.  
  29.    { 
  30.  
  31.        // do something 
  32.  
  33.    } 
  34.  
  35.  
  36.  
  37.    private function mkTxt (string $txtName) :void 
  38.  
  39.    { 
  40.  
  41.        // do something 
  42.  
  43.    } 
  44.  
  45.  
  46.  
  47.    public function write (string $msg) 
  48.  
  49.    { 
  50.  
  51.        // do something 
  52.  
  53.    } 
  54.  
  55. } 
  56.  
  57.  
  58.  
  59. class RedisLog implements Log 
  60.  
  61. { 
  62.  
  63.    private $redis = null; 
  64.  
  65.    private $key = ''; 
  66.  
  67.  
  68.  
  69.    public function __construct(string $key) 
  70.  
  71.    { 
  72.  
  73.        $this->redis = '...'; // 获取redis实例 
  74.  
  75.        $this->key = $key; 
  76.  
  77.        // ... 
  78.  
  79.    } 
  80.  
  81.  
  82.  
  83.    public function write (string $msg) 
  84.  
  85.    { 
  86.  
  87.        // do something 
  88.  
  89.    } 
  90.  
  91. } 
  92.  
  93.  
  94.  
  95. class App 
  96.  
  97. { 
  98.  
  99.    public function run () 
  100.  
  101.    { 
  102.  
  103.        // do something 
  104.  
  105.  
  106.  
  107.        // 记录日志 
  108.  
  109.        (new RedisLog('log'))->write('框架运行信息记录'); 
  110.  
  111.    } 
  112.  
  113. } 

可以看到,App类依赖RedisLog类,如果我们今后不再使用redis来记录日子,而改用文本文件的话,那么就需要修改run里面的代码。

现在,我们换成使用依赖注入这种技巧来改写,代码如下;

  1. class App 
  2.  
  3. { 
  4.  
  5.    private $logHandle = null; 
  6.  
  7.  
  8.  
  9.    public function __construct(Log $log) 
  10.  
  11.    { 
  12.  
  13.        $this->logHandle = $log; 
  14.  
  15.    } 
  16.  
  17.  
  18.  
  19.    public function run () 
  20.  
  21.    { 
  22.  
  23.        // do something 
  24.  
  25.  
  26.  
  27.        // 记录日志 
  28.  
  29.        $this->logHandle->write('框架运行信息记录'); 
  30.  
  31.    } 
  32.  
  33. } 

改写后的App类不再依赖RedisLog类,可以随时换成其他的Log类,只要该类实现了write方法即可。可以看到,使用了依赖注入,可以灵活的替换掉所依赖的类,另外它是编写可测试代码最有效的手段。

Tags: php依赖注入

分享到: