DIY 實現 ThinkPHP 核心框架(八)控制反轉和依賴注入

cn-five發表於2020-09-02

軟體工程提倡高內聚、低耦合,控制反轉是一種有效的設計原則,而依賴注入是控制反轉的一種實現方式。有以下程式碼

class Demo
{
    public function show()
    {
        $test = new Test();
    }
}

如果不例項化 Test 類, Demo 類也就沒有意義。但是這種關係會增加程式碼的耦合性,如果 Test 類例項化方式改變, Demo 程式碼也要隨之更改。如果類似的情況很多,專案程式碼會顯得凌亂。
為解決這個問題, ThinkPHP 提供了一個容器類 Container , 建立 Test 例項的任務交由 Container類 完成,將 Test 例項作為引數傳給 Demo 類的 show() 方法。
將建立例項的控制權交給 Container 類實現控制反轉,而 show() 方法依賴的 Test 類通過引數從外部傳入實現依賴注入。

class Demo
{
    public function show(Test $test)
    {}
}

建立 core/src/think/Container.php 檔案

namespace think;

//use ReflectionClass;
//use ReflectionFunctionAbstract;
/**
 * 以下屬性、方法的程式碼 ThinkPHP 5 與 6 中基本保持一致
 * 採用“拿來主義”
 * Class Container
 * @package think
 */
class Container
{
    protected  $instances = [];

    public function make (string $class)
    {
        $class = '\\think\\' . $class;
        if (!isset($this->instances[$class])) {
            $this->instances[$class] = new $class();
        }
        return $this->instances[$class];
    }

    public function show()
    {
        $request = $this->make('Request');
        $index = new \app\index\controller\Index();
        $index->show($request);
    }
}

建立 core/src/think/Request.php 檔案

namespace think;

class Request
{}

修改 application/index/controller/Index.php , 引入 Request 類的名稱空間,編寫 show() 方法接受 Request 類的例項引數 $req 。

namespace app\index\controller;

use think\Request;

class Index
{
    public function show (Request $req)
    {
        var_dump($req instanceof Request);
    }
}

修改入口檔案 public/index.php 進行測試

require __DIR__ . '/../core/base.php';

(new \think\Container)->show();

訪問 diy.tp ,執行結果為 bool(true) 說明成功實現依賴注入。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章