以前看了好多框架,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"; ?>
最后的结果以下数组