實現一個簡單的di容器

以前看了好多框架,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";


?>

最後的結果以下
圖片描述數組

相關文章
相關標籤/搜索