Рубрики
Uncategorized

Реализация простого контейнера Di

Автор оригинала: David Wong.

Я видел много фреймворков раньше, laravel , thinkphp , Yii и так далее. В основном используются контейнеры. Что касается меня, хотя я понимаю, как пишет ларавель, если я не попробую, я всегда думаю, что это не сработает.

Следующий код представляет собой простой контейнер, который я реализовал. Во многих местах это не очень хорошо обрабатывается, но этого должно быть достаточно.

php

class Container{
    
    // The variable $binds is saved as a mapping of the name=> instance
    private $binds = [];


    public static $instance = null;

    /**
     * single case
     */
    public static function getInstance(){
        if(static::$instance == null){
            static::$instance = new static();
            return static::$instance ;
        }
        return static::$instance;
    }

    /**
     * At first it was influenced by laravel, so I wrote a bind function.
     * After looking at the container implementation of laravel, I was impressed by the $concrete and $abstract back-and-forth transformations.
     * The following code is a little bit like the implementation in thinkphp, a little more understandable
     */
    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{
            // Start making an array here, laravel seems to be separate from make and build.
            static::getInstance()->make($name);
        }
        
    }

    /**
     * The core is the make method.
     */
    public static function get($name){
        return static::getInstance()->make($name);
    }

    /**
     * Core make method
     */
    public function make($name){
        try{
            // Find if the $this - > binds instance already exists based on the class name, and return it directly if it exists.
            if(array_key_exists($name,$this->binds)){
                return $this->binds[$name];
            }
            // Get its reflection class from the class name
            $reflectClass = new ReflectionClass($name);
            // Using Reflective Classes
            $constructor = $reflectClass->getConstructor();
            // If there is no constructor, instantiate it directly
            $params = [];
            if(!is_null($constructor)){
                // Getting the method in the constructor
                $constructorParams = $constructor->getParameters();
                // var_dump($constructorParams);
                // Save constructor parameters
                foreach($constructorParams as $constructorParam){
                    // This place is mainly to determine whether the parameter is a class, and if it is constructed recursively, is it simply added to $this - > params?
                    if(!is_null($constructorParam->getType())){
                        $params[] =$this->make($constructorParam->name,$constructorParam->name);
                    }else{
                        $params[] = $constructorParam->name;
                    }
                }
            }
            // An example of tectonics in this place
            $class = $reflectClass->newInstanceArgs($params);
            // binding
            $this->binds[$name] = $class;
            return $class;
        }catch(ReflectionException $e){
            echo $e->getMessage();
        }
    }

    private function __construct(){}
    private function __clone(){}

}
?>

Вот мой тестовый файл.

name;
    }

    public function sayDI2Name(DI2 $di2){
        // If so, the di2 method prints out before the previous string
        // 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;
    }   
}

// It doesn't matter whether you want it or not.
// 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";


?>

Окончательные результаты таковы.

Оригинал: “https://developpaper.com/implementing-a-simple-di-container/”