实现一个简单的di容器

57次阅读

共计 2965 个字符,预计需要花费 8 分钟才能阅读完成。

之前看了好多框架,laravel,thinkphp,yii 等等。基本上都使用了容器。对于我而言,虽然看懂了 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(){}

}
?>
下面是我的测试文件了,
<?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”;

?>
最后的结果如下

正文完
 0