关于依赖注入的思考
最近几日接触了一个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 */
每一天都是崭新的