php 的一個依賴注入容器, 說白了,就是用php 的反射類,來在運行的時候動態的分析類具有的函數,以及動態分析函數的參數, 從而實例化類,並執行類的方法。
另外,php 中的 typehint 還是很有用的,反射的時候就有用到!
下面貼出代碼:
<?php class Bim { public function doSomething() { echo __METHOD__, '|'; } } class Bar { private $bim; public function __construct(Bim $bim) { $this->bim = $bim; } public function doSomething() { $this->bim->doSomething(); echo __METHOD__, '|'; } } class Foo { private $bar; public function __construct(Bar $bar) { $this->bar = $bar; } public function doSomething() { $this->bar->doSomething(); echo __METHOD__; } } class Container { private $s = array(); public function __set($k, $c) { $this->s[$k] = $c; } public function __get($k) { // return $this->s[$k]($this); return $this->build($this->s[$k]); } /** * 自動綁定(Autowiring)自動解析(Automatic Resolution) * * @param string $className * @return object * @throws Exception */ public function build($className) { echo "<pre>";var_dump($className); // 如果是匿名函數(Anonymous functions),也叫閉包函數(closures) if ($className instanceof Closure) { // 執行閉包函數,並將結果 return $className($this); } /** @var ReflectionClass $reflector */ $reflector = new ReflectionClass($className); // 檢查類是否可實例化, 排除抽象類abstract和對象接口interface if (!$reflector->isInstantiable()) { throw new Exception("Can't instantiate this."); } /** @var ReflectionMethod $constructor 獲取類的構造函數 */ $constructor = $reflector->getConstructor(); // 若無構造函數,直接實例化並返回 if (is_null($constructor)) { return new $className; } // 取構造函數參數,通過 ReflectionParameter 數組返回參數列表 $parameters = $constructor->getParameters(); // 遞歸解析構造函數的參數 $dependencies = $this->getDependencies($parameters); // 創建一個類的新實例,給出的參數將傳遞到類的構造函數。 return $reflector->newInstanceArgs($dependencies); } /** * @param array $parameters * @return array * @throws Exception */ public function getDependencies($parameters) { $dependencies = []; /** @var ReflectionParameter $parameter */ foreach ($parameters as $parameter) { /** @var ReflectionClass $dependency */ $dependency = $parameter->getClass(); if (is_null($dependency)) { // 是變量,有默認值則設置默認值 $dependencies[] = $this->resolveNonClass($parameter); } else { // 是一個類,遞歸解析 $dependencies[] = $this->build($dependency->name); } } return $dependencies; } /** * @param ReflectionParameter $parameter * @return mixed * @throws Exception */ public function resolveNonClass($parameter) { // 有默認值則返回默認值 if ($parameter->isDefaultValueAvailable()) { return $parameter->getDefaultValue(); } throw new Exception('I have no idea what to do here.'); } } // ---- //$c = new Container(); //$c->bar = 'Bar'; //$c->foo = function ($c) { // return new Foo($c->bar); //}; //// 從容器中取得Foo //$foo = $c->foo; //$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething ///*// ---- $di = new Container(); // $di->foo = 'Foo'; // ///** @var Foo $foo */ $foo = $di->foo; // var_dump($foo);exit; echo "<pre>";var_dump($foo->doSomething()); var_dump( get_class($foo)); die(); ///* //Foo#10 (1) { // private $bar => // class Bar#14 (1) { // private $bim => // class Bim#16 (0) { // } // } //} //*/ // $foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething*/