首頁  >  文章  >  後端開發  >  PHP控制反轉和依賴注入實例

PHP控制反轉和依賴注入實例

小云云
小云云原創
2018-03-22 09:23:192403瀏覽

本文主要和大家分享PHP控制反轉和依賴注入實例,依賴注入的目的是實現鬆散耦合的軟體架構,以便更好的測試,管理和擴展的程式碼。

控制反轉(Inversion of Control):當呼叫者需要被呼叫者的協助時,在傳統的程式設計過程中,通常由呼叫者來建立被呼叫者的實例,但在這裡,創建被呼叫者的工作不再由呼叫者來完成,而是將被呼叫者的創建移到呼叫者的外部,從而反轉被呼叫者的創建,消除了調用者對被呼叫者所建立的控制,因此稱為控制反轉。

依賴注入(Dependency Injection):要實現控制反轉,通常的解決方案是將建立被呼叫者實例的工作交由IoC容器來完成,然後在呼叫者中注入被呼叫者(透過建構器/方法注入實作),這樣我們就實作了呼叫者與被呼叫者的解耦,該過程稱為依賴注入。依賴注入是控制反轉的一種實作方式。常見注入方式有三種:setter、constructor injection、property injection。

容器(Container):管理物件的產生、資源取得、銷毀等生命週期,建立物件與物件之間的依賴關係,可以延時載入物件。比較著名有PHP-DI、Pimple。

程式碼示範IoC:

假設應用程式有儲存需求,若直接在高層的應用程式中呼叫低層模組API,導致應用程式對低層模組產生依賴。

<?php
/**
 * 高层
 */
class App
{
    private $writer;

    public function __construct()
    {
        $this->writer = new FloppyWriter();
    }

    public function save()
    {
        $this->writer->saveToFloppy();
    }
}

/**
 * 低层,软盘存储
 */
class FloppyWriter
{
    public function saveToFloppy()
    {
        echo __METHOD__;
    }
}

$app = new App();
$app->save(); // FloppyWriter::saveToFloppy

假設程式要移植到另一個平台,而該平台使用USB磁碟作為儲存介質,則這個程式無法直接重複使用,必須加以修改才行。本例由於低層變化導致高層也跟著變化,不好的設計。程式不應該依賴具體的實現,而是要依賴抽像的介面。請看程式碼示範:

<?php
/**
 * 接口
 */
interface IDeviceWriter
{
    public function saveToDevice();
}

/**
 * 高层
 */
class App
{
    /**
     * @var IDeviceWriter
     */
    private $writer;

    /**
     * @param IDeviceWriter $writer
     */
    public function setWriter($writer)
    {
        $this->writer = $writer;
    }

    public function save()
    {
        $this->writer->saveToDevice();
    }
}

/**
 * 低层,软盘存储
 */
class FloppyWriter implements IDeviceWriter
{

    public function saveToDevice()
    {
        echo __METHOD__;
    }
}

/**
 * 低层,USB盘存储
 */
class UsbDiskWriter implements IDeviceWriter
{

    public function saveToDevice()
    {
        echo __METHOD__;
    }
}

$app = new App();
$app->setWriter(new UsbDiskWriter());
$app->save(); // UsbDiskWriter::saveToDevice

$app->setWriter(new FloppyWriter());
$app->save(); // FloppyWriter::saveToDevice

控制權從實際的FloppyWriter轉移到了抽象的IDeviceWriter介面上,讓App依賴IDeviceWriter接口,且FloppyWriter、UsbDiskWriter也依賴IDeviceWriter介面。
這就是IoC,面對變化,高層不用修改一行程式碼,不再依賴低層,而是依賴注入,這就引出了DI。

如果這個元件有很多依賴,我們需要建立多個參數的setter方法來傳遞依賴關係,這讓我們的程式碼不易維護。

<?php
//创建依赖实例
$request = new Request();
$filter = new Filter();

//把实例作为参数传递给构造函数
$some = new SomeComponent($request, $filter);

$some->setRequest($request);
$some->setFilter($filter);


解決的方法是為依賴實例提供一個容器。這個容器擔任全域的註冊表,注入容器而不是具體實例。

<?php
class SomeComponent
{

    protected $_di;

    public function __construct($di)
    {
        $this->_di = $di;
    }

    public function someRequest()
    {

        // 请求实例
        $connection = $this->_di->get(&#39;request&#39;);

    }

    public function someOtherRequest()
    {

        // 请求实例
        $connection = $this->_di->get(&#39;request&#39;);

        // 过滤器实例
        $filter = $this->_di->get(&#39;filter&#39;);

    }

}

$di = new DI();

//在容器中注册一个request服务
$di->set(&#39;request&#39;, function() {
    return new Request(array(
        "test" => "test"
    ));
});

//在容器中注册一个filter服务
$di->set(&#39;filter&#39;, function() {
    return new Filter();
});

//把传递服务的容器作为唯一参数传递给组件
$some = new SomeComponent($di);
$some->someRequest();

這個元件現在可以很簡單的取得到它所需要的服務,服務採用延遲載入的方式,只有在需要使用的時候才初始化,這也節省了伺服器資源。這個組件現在是高度解耦。
相關建議:

解析PHP依賴注入與控制反轉

#PHP 依賴注入(DI) 與 控制反轉(IoC)實例教學

PHP控制反轉與依賴注入

以上是PHP控制反轉和依賴注入實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn