关于依赖注入的思考

最近几日接触了一个PHP API框架,其中里面用到了依赖注入的思想。于是自己写下了一个小例子来加深印象:

  1 <?php
  2 //https://docs.phalconphp.com/zh/latest/reference/di.html
  3 /**
  4  * Log接口
  5  * Interface ILog
  6  */
  7 interface ILog {
  8     public function info($str);
  9 
 10     public function error($str);
 11 }
 12 
 13 /**
 14  * 数据库log,实现log接口
 15  * Class DBLog
 16  */
 17 class DBLog implements ILog {
 18     private $_name;
 19 
 20     public function __construct($name) {
 21         $this->_name = $name;
 22     }
 23 
 24     public function info($str) {
 25         echo '<br>[DBLog][' . $this->_name . '][info]call log info function: ' . $str . '<br>';
 26     }
 27 
 28     public function error($str) {
 29         echo '<br>[DBLog][' . $this->_name . '][error]call log info function: ' . $str . '<br>';
 30     }
 31 }
 32 
 33 /**
 34  * 文件log,实现log接口
 35  * Class FileLog
 36  */
 37 class FileLog implements ILog {
 38     private $_name;
 39 
 40     public function __construct($name) {
 41         $this->_name = $name;
 42     }
 43 
 44     public function info($str) {
 45         echo '<br>[FileLog][' . $this->_name . '][info]call log info function: ' . $str . '<br>';
 46     }
 47 
 48     public function error($str) {
 49         echo '<br>[FileLog][' . $this->_name . '][error]call log info function: ' . $str . '<br>';
 50     }
 51 }
 52 
 53 /**
 54  * 依赖注入类
 55  * 用于存放需要依赖的类的容器
 56  * Class DI
 57  */
 58 class DI {
 59     public $arr = array();
 60     protected static $instance = NULL;
 61 
 62     public static function getInstance() {//单例加载
 63         if (self::$instance == NULL) {
 64             self::$instance = new DI();
 65         }
 66         return self::$instance;
 67     }
 68 
 69     public function __set($name, $value) {//魔法方法 设置私有属性值
 70         $this->set($name, $value);
 71     }
 72 
 73     public function __get($name) {
 74         $this->get($name);
 75     }
 76 
 77     public function set($key, $value) {
 78         $this->arr[$key] = $value;
 79     }
 80 
 81     public function get($key, $default = NULL) {
 82         return $this->arr[$key];
 83     }
 84 }
 85 
 86 /**
 87  * 主类
 88  * Class User
 89  */
 90 class User {
 91 
 92     private $_di;
 93 
 94     public function __construct($di) {
 95         //使用依赖注入容器,目的是防止出现多个setter方法分别设置不同依赖项
 96         $this->_di = $di;
 97     }
 98 
 99     public function writeLog($str) {
100         //从DI容器中获取要操作的类/对象
101         $obj = $this->_di->get('logger');
102         $obj->info($str);
103         $obj->error($str);
104     }
105 
106     public function run() {
107         $obj = $this->_di->get('fun');
108         $obj()->callRuntime();
109     }
110 }
111 
112 class Runtime {
113     public function __construct() {
114         var_dump('call Runtime construct');
115     }
116 
117     public function callRuntime() {
118         var_dump('call Runtime');
119     }
120 }
121 
122 //客户端调用
123 echo '<br>=======begin========<br>';
124 $di = DI::getInstance();
125 $di->logger = new DBLog('mydb');//魔法方法 设置私有属性值
126 $user = new User($di);
127 $user->writeLog('lalala');
128 
129 echo '<br>===============<br>';
130 $di2 = DI::getInstance();
131 $di2->logger = new FileLog('myfile');
132 
133 $di2->fun = function () {//延迟加载
134     return new Runtime();
135 };
136 
137 
138 //$di2->set('logger',new FileLog('myfile')); 与上面的方式等效
139 $user2 = new User($di2);//切换依赖项,主类(User类)不需要改一行代码(前提是不同依赖项实现相同的接口)
140 $user2->writeLog('bababa');
141 $user2->run();
142 echo '<br>=======end========<br>';
143 
144 //返回结果:
145 /*
146 
147 =======begin========
148 
149 [DBLog][mydb][info]call log info function: lalala
150 
151 [DBLog][mydb][error]call log info function: lalala
152 
153 ===============
154 
155 [FileLog][myfile][info]call log info function: bababa
156 
157 [FileLog][myfile][error]call log info function: bababa
158 
159 string 'call Runtime construct' (length=22)
160 
161 string 'call Runtime' (length=12)
162 
163 
164 =======end========
165 */
原文地址:https://www.cnblogs.com/dannywang/p/4740386.html