依赖注入模式

 

1. https://my.oschina.net/cxz001/blog/533166

 

依赖注入(Dependency Injection)是控制反转(Inversion of Control)的一种实现方式。

我们先来看看什么是控制反转。
  当调用者需要被调用者的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,但在这里,创建被调用者的工作不再由调用者来完成,
而是将被调用者的创建移到调用者的外部,从而反转被调用者的创建,消除了调用者对被调用者创建的控制,因此称为控制反转。
  要实现控制反转,通常的解决方案是将创建被调用者实例的工作交由 IoC 容器来完成,然后在调用者中注入被调用者(通过构造器/方法注入实现),这样我们就实现了调用者与被调用者的解耦,该过程被称为依赖注入。
依赖注入不是目的,它是一系列工具和手段,最终的目的是帮助我们开发出松散耦合(loose coupled)、可维护、可测试的代码和程序。这条原则的做法是大家熟知的面向接口,或者说是面向抽象编程。

 

下面是一个简化版本的Ioc容器, 完整版的可以观看相应框架的实现

  1 <?php
  2 
  3 /**
  4  * Ioc容器,这个是简化版本的,有些特性还是没有包含的
  5  */
  6 class Di implements \ArrayAccess{
  7     private $_bindings = [];        //服务列表
  8     private $_instances = [];       //已经实例化的服务
  9 
 10     //获取服务
 11     public function get($name, $params=[]){
 12         //先从已经实例化的列表中查找
 13         if(isset($this->_instances[$name])){
 14             return $this->_instances[$name];
 15         }
 16 
 17         //检测有没有注册该服务
 18         if(!isset($this->_bindings[$name])){
 19             return null;
 20         }
 21 
 22         $concrete = $this->_bindings[$name]['class'];//对象具体注册内容
 23 
 24         $obj = null;
 25         //匿名函数方式
 26         if($concrete instanceof \Closure){
 27             $obj = call_user_func_array($concrete,$params);
 28         }
 29         //字符串方式
 30         elseif(is_string($concrete)){
 31             if(empty($params)){
 32                 $obj = new $concrete;
 33             }else{
 34                 //带参数的类实例化,使用反射
 35                 $class = new \ReflectionClass($concrete);
 36                 $obj = $class->newInstanceArgs($params);
 37             }
 38         }
 39 
 40         //如果是共享服务,则写入_instances列表,下次直接取回
 41         if($this->_bindings[$name]['shared'] == true && $obj){
 42             $this->_instances[$name] = $obj;
 43         }
 44 
 45         return $obj;
 46     }
 47 
 48     //检测是否已经绑定
 49     public function has($name){
 50         return isset($this->_bindings[$name]) or isset($this->_instances[$name]);
 51     }
 52 
 53     //卸载服务
 54     public function remove($name){
 55         unset($this->_bindings[$name], $this->_instances[$name]);
 56     }
 57 
 58     //设置服务
 59     public function set($name,$class){
 60         $this->_registerService($name, $class);
 61     }
 62 
 63     //设置共享服务
 64     public function setShared($name,$class){
 65         $this->_registerService($name, $class, true);
 66     }
 67 
 68 
 69 
 70 
 71 
 72     //注册服务
 73     private function _registerService($name,$class,$shared=false){
 74         $this->remove($name);
 75 
 76         if(!($class instanceof \Closure) && is_object($class)){
 77             $this->_instances[$name] = $class;
 78         }else{
 79             $this->_bindings[$name] = array("class"=>$class,"shared"=>$shared);
 80         }
 81     }
 82 
 83     //ArrayAccess接口,检测服务是否存在
 84     public function offsetExists($offset) {
 85         return $this->has($offset);
 86     }
 87 
 88     //ArrayAccess接口,以$di[$name]方式获取服务
 89     public function offsetGet($offset) {
 90         return $this->get($offset);
 91     }
 92 
 93     //ArrayAccess接口,以$di[$name]=$value方式注册服务,非共享
 94     public function offsetSet($offset, $value) {
 95         return $this->set($offset,$value);
 96     }
 97 
 98     //ArrayAccess接口,以unset($di[$name])方式卸载服务
 99     public function offsetUnset($offset) {
100         return $this->remove($offset);
101     }
102 }
103 
104 
105 
106 
107 
108 header("Content-Type:text/html;charset=utf8");
109 class A{
110     public $name;
111 
112     public function __construct($name=""){
113         $this->name = $name;
114     }
115 }
116 
117 $di = new Di();
118 
119 
120 //匿名函数方式注册一个名为a1的服务
121 $di->setShared('a1',function($name=""){
122     return new A($name);
123 });
124 
125 $a1 = $di->get('a1',array("小李"));
126 echo $a1->name."<br/>";//小李
127 
128 $a1_1 = $di->get('a1',array("小王"));
129 echo $a1->name."<br/>";//小李
130 echo $a1_1->name."<br/>";//小李
131 
132 
133 
134 //直接以类名方式注册
135 $di->set('a2','A');
136 
137 $a2 = $di->get('a2',array("小张"));
138 echo $a2->name."<br/>";//小张
139 $a2_1 = $di->get('a2',array("小徐"));
140 echo $a2->name."<br/>";//小张
141 echo $a2_1->name."<br/>";//小徐
142 
143 
144 
145 //直接传入实例化的对象
146 $di->set('a3',new A("小唐"));
147 
148 $a3 = $di['a3'];//可以直接通过数组方式获取服务对象
149 echo $a3->name."<br/>";//小唐
150 
151 
152 
153 
154 
155 
156 
157 //删除服务则可以通过
158 unset($di['a1']);
159 
160 or
161 
162 $di->remove('a1');
163 
164 
165 //判断是否包含一个服务可以通过
166 isset($di['a1']);
167 
168 or
169 
170 $di->has('a1');
View Code

 

posted @ 2017-01-05 01:38  _logan  阅读(232)  评论(0编辑  收藏  举报