php 自动绑定di容器实现
1 <?php 2 3 class Bim 4 { 5 public function doSth() 6 { 7 echo __METHOD__.PHP_EOL; 8 } 9 } 10 11 class Bar 12 { 13 protected $bim; 14 15 public function __construct(Bim $bim) 16 { 17 $this->bim = $bim; 18 } 19 20 public function doSth() 21 { 22 $this->bim->doSth(); 23 echo __METHOD__.PHP_EOL; 24 } 25 } 26 27 class Bar2 extends Bar 28 { 29 protected $bim; 30 31 public function doSth() 32 { 33 $this->bim->doSth(); 34 echo __METHOD__.PHP_EOL; 35 } 36 } 37 38 class Foo 39 { 40 private $bar; 41 42 public function __construct(Bar $bar) 43 { 44 $this->bar = $bar; 45 } 46 47 public function doSth() 48 { 49 $this->bar->doSth(); 50 echo __METHOD__.PHP_EOL; 51 } 52 } 53 54 class Container 55 { 56 private $s = []; 57 58 public function __set($k, $c) 59 { 60 $this->s[$k] = $c; 61 } 62 63 public function __get($k) 64 { 65 return $this->s[$k]($this); 66 } 67 } 68 69 class Container2 70 { 71 private $s = []; 72 73 public function __set($k, $c) 74 { 75 $this->s[$k] = $c; 76 } 77 78 public function __get($k) 79 { 80 if (!$this->s[$k]) { 81 return false; 82 } 83 return $this->build($this->s[$k]); 84 } 85 86 public function build($className) 87 { 88 if ($className instanceof Closure) { 89 return $className($this); 90 } 91 92 try { 93 $reflector = new ReflectionClass($className); 94 } catch (\ReflectionException $e) { 95 echo $className.'类反射异常'.PHP_EOL; 96 echo $e->getMessage(); 97 } 98 99 #检查类是否可实例化, 排除抽象类abstract和对象接口interface 100 if (!$reflector->isInstantiable()) { 101 throw new Exception("Can't instantiate this."); 102 } 103 104 $constructor = $reflector->getConstructor(); 105 106 #如果没有构造函数, 直接实例化并返回 107 if (is_null($constructor)) { 108 return new $className; 109 } 110 111 $parameters = $constructor->getParameters(); 112 113 #递归解析构造函数的参数 114 $dependencies = $this->getDependencies($parameters); 115 116 #创建一个类的新实例,给出的参数将传递到类的构造函数. 117 return $reflector->newInstanceArgs($dependencies); 118 } 119 120 public function getDependencies($parameters) 121 { 122 $dependencies = []; 123 124 foreach ($parameters as $parameter) { 125 $dependency = $parameter->getClass(); 126 127 if (is_null($dependency)) { 128 $dependencies[] = $this->resolveNonClass($parameter); 129 } else { 130 #是一个类,递归解析 131 $className = lcfirst($dependency->name); 132 #先取出容器中绑定的类 否则自动绑定 133 if ($this->s[$className]) { 134 $dependencies[] = $this->$className; 135 } else { 136 $dependencies[] = $this->build($dependency->name); 137 } 138 } 139 } 140 141 return $dependencies; 142 } 143 144 public function resolveNonClass($parameter) 145 { 146 // 有默认值则返回默认值 147 if ($parameter->isDefaultValueAvailable()) { 148 return $parameter->getDefaultValue(); 149 } 150 throw new Exception('I have no idea what to do here.'); 151 } 152 } 153 154 // 依赖注入模式 155 //$foo = new Foo(new Bar(new Bim())); 156 157 #di模式 158 // $c = new Container(); 159 // $c->bim = function() { 160 // return new Bim(); 161 // }; 162 // $c->bar = function($c) { 163 // return new Bar($c->bim); 164 // }; 165 // $c->foo = function($c) { 166 // return new Foo($c->bar); 167 // }; 168 169 #实现了自动绑定 170 #1向di中注册类 171 $c = new Container2(); 172 $c->bim = 'Bim'; 173 #$c->bar = 'Bar2'; #实现了自动绑定 如果没有注册类的化就按自动加载去寻找类 174 $c->foo = 'Foo'; 175 // $c->bar = 'Bar'; 176 // $c->foo = function ($c) { 177 // return new Foo($c->bar); 178 // }; 179 // 从容器中取得Foo 180 $foo = $c->foo; 181 $foo->doSth();
参考:https://segmentfault.com/a/1190000002424023