以前看了好多框架,laravel,thinkphp,yii等等。基本上都使用了容器。對於我而言,雖然看懂了laravel是怎麼寫的,可是若是本身不去嘗試一下,始終以爲不會這個東西。php
下面的代碼是我實現的一個簡單的容器,不少地方處理並非很好,可是應該已經足夠了。laravel
<?php class Container{ //$binds 這個變量保存,是名字=>實例的映射 private $binds = []; public static $instance = null; /** * 單例 */ public static function getInstance(){ if(static::$instance == null){ static::$instance = new static(); return static::$instance ; } return static::$instance; } /** * 一開始是受到laravel的影響,因此寫了一個bind函數, * 看完laravel的容器實現,印象之中,$concrete和$abstract來回變換。 * 下面的代碼有點像thinkphp的裏面的實現,好理解一點 */ public static function bind($name,$class = null){ if($class instanceof Closure){ static::getInstance()->binds[$name] = $class; }else if(is_object($class)){ static::getInstance()->binds[$name] = $class; }else{ //在這裏開始make一個數組,laravel好像是make和build分開的。 static::getInstance()->make($name); } } /** * 核心是make方法了 */ public static function get($name){ return static::getInstance()->make($name); } /** * 核心make方法 */ public function make($name){ try{ //根據類名去查找$this->binds實例是否已經存在,若是存在就直接返回 if(array_key_exists($name,$this->binds)){ return $this->binds[$name]; } //根據類名獲得它的反射類 $reflectClass = new ReflectionClass($name); //利用反射類 $constructor = $reflectClass->getConstructor(); //若是沒有構造器的話,就直接去實例化它 $params = []; if(!is_null($constructor)){ //獲取構造器中的方法 $constructorParams = $constructor->getParameters(); // var_dump($constructorParams); //保存構造器的參數 foreach($constructorParams as $constructorParam){ //這個地方主要是判斷參數是不是類,若是是就遞歸的構造它,不是就簡單的添加到$this->params中 if(!is_null($constructorParam->getType())){ $params[] =$this->make($constructorParam->name,$constructorParam->name); }else{ $params[] = $constructorParam->name; } } } //在這個地方構造實例 $class = $reflectClass->newInstanceArgs($params); //綁定 $this->binds[$name] = $class; return $class; }catch(ReflectionException $e){ echo $e->getMessage(); } } private function __construct(){} private function __clone(){} } ?>
下面是個人測試文件了,thinkphp
<?php require "./Container.php"; class TestFather{ private $name = "TestFather"; public function __construct(){ } } class Test extends TestFather{ private $name = "Test"; // public function __construct(DI $di, DI2 $di2,$name){ // } public function __construct(DI $di,$name,$param_2 =[]){ } public function sayName(){ echo $this->name; } public function sayDI2Name(DI2 $di2){ //若是這麼寫的,di2方法會先於前面的字符串打印出來 // echo "form Test say di2 name: ".$di2->sayName(); echo "form Test say di2 name: "; echo $di2->sayName(); } } class DI{ private $name = "DI"; public function __construct(DI2 $di2){} public function sayName(){ echo $this->name; } } class DI2{ private $name = "DI2"; public function __construct(){} public function sayName(){ echo $this->name; } } class DI3{ private $name = "DI3"; public function __construct(){} public function sayName(){ echo $this->name; } } class DI4{ private $name = "DI4"; public function __construct(){} public function sayName(){ echo $this->name; } } //要不要無所謂了 // Container::bind('test','Test'); $test = Container::get('test'); $test->sayName(); echo "\n"; $test->sayDI2Name(new DI2()); echo "\n"; $di = Container::get('di'); $di->sayName(); echo "\n"; $di2 = Container::get('di2'); $di2->sayName(); echo "\n"; $di3 = new DI3(); Container::get('di3',$di3)->sayName(); echo "\n"; $di4 = function(){ return new DI4(); }; Container::get('di4',$di4)->sayName(); echo "\n"; ?>
最後的結果以下數組