源碼-反轉控制的理解

源碼-反轉控制的理解

反轉控制是什麼,有什麼用:反轉控制爲Ioc Container,簡稱ICO,解決各個類之間的依賴問題。主流框架(laravel、yii等)源碼均有出現,若不能理解反轉控制,對源碼的理解就很難深入。

  • 功能是什麼
    1、存儲定義的類
    2、實例化類

案例說明-簡易案例

//容器類,封裝的很簡單,set方法用於存儲類,get用於實例化類
Class Container
{
    private $_definitions;

//定義類
    public function set($class, $definition)
    {
        $this->_definitions[$class] = $definition;
    }

//實例化類  call_user_func:第一個參數 callback 是被調用的回調函數,其餘參數是回調函數的參數。
    public function get($class, $params = [])
    {
        $definition = $this->_definitions[$class];
        return call_user_func($definition, $params);
    }
}
//構造賦值屬性
class EmailSenderBy163
{
    private $_name;

    public function __construct($name = '')
    {
        $this->_name = $name;
    }

    public function send()
    {
    }
}


$container = new Container;
$container->set('EmailSenderBy163', function ($name = '') {
//函數追加new自己函數
    return new EmailSenderBy163($name);
});
//啓動new函數new自己
$emailSenderBy163 = $container->get('EmailSenderBy163', '163');

echo "<pre>";
print_r($emailSenderBy163);
//打印出來的結果
EmailSenderBy163 Object
(
    [_name:EmailSenderBy163:private] => 163
)

上述不太好理解,我還用思維導圖做了圖讓你理解,絕對貼心
這裏寫圖片描述

案例說明-複雜案例

//沒什麼好說,一個類構造賦值屬性
class EmailSenderBy163
{
    private $_name;

    public function __construct($name = '')
    {
        $this->_name = $name;
    }

    public function send()
    {
    }
}

class User
{
    private $_emailSenderObject;

    //構造賦值並限制$emailSenderObject爲EmailSenderBy163 類和子類爲
    public function __construct(EmailSenderBy163 $emailSenderObject)
    {
        $this->_emailSenderObject = $emailSenderObject;
    }

    public function register()
    {
        $this->_emailSenderObject->send();
    }
}
//容器
Class Container
{
    private $_definitions;

    public function set($class, $definition)
    {
        $this->_definitions[$class] = $definition;
    }

    public function get($class, $params = [])
    {
    //get方法在判斷回調函數上更加嚴謹
        if (isset($this->_definitions[$class]) && is_callable($this->_definitions[$class], true)) {
            $definition = $this->_definitions[$class];
            //$this是指這個容器
            return call_user_func($definition, $this, $params);
        } else {
            throw new Exception("error");
        }
    }
}


$container = new Container;

$container->set('EmailSenderBy163', function ($container, $name = '') {
    return new EmailSenderBy163($name);
});
$container->set('User', function ($container, $params = []) {
//$container對應上述的$this,這樣拿到相對應參數,這裏有點繞想想會明白的
    return new User($container->get($params[0], $params[1]));
});

echo '<pre>';
print_r($container->get('EmailSenderBy163', ['163']));
print_r($container->get('User', ['EmailSenderBy163', '163']));

這就是反轉控制,需要先把所有的類全部set進去,然後get的時候指定其所依賴的類,依然很麻煩。可以考慮使用反射,並做自動實例化處理。
反射類地址:http://php.net/manual/zh/book.reflection.php

利用反射增加容器類

Class Container
{
    public function get($class, $params = [])
    {
        return $this->build($class, $params);
    }

    public function build($class, $params)
    {
        $dependencies = [];
    //實例化反射類
        $reflection = new ReflectionClass($class);
        //獲取類的構造函數
        $constructor = $reflection->getConstructor();
        if ($constructor !== null) {
        //獲取參數
            foreach ($constructor->getParameters() as $param) {
            //獲得類的提示類型
                $c = $param->getClass();
                if ($c !== null) {
                //獲取類名
                    $dependencies[] = $this->get($c->getName(), $params);
                }
            }
        }

        foreach ($params as $index => $param) {
            $dependencies[$index] = $param;
        }
//從給出的參數創建一個新的類實例
        return $reflection->newInstanceArgs($dependencies);
    }
}

$container = new Container;
$user = $container->get('User');
echo '<pre>';
print_r($user);

輸出結果

User Object
(
    [_emailSenderObject:User:private] => EmailSenderBy163 Object
        (
            [_name:EmailSenderBy163:private] => 
        )

)
發佈了47 篇原創文章 · 獲贊 74 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章