99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

參考:理解PHP 依賴注入|Laravel IoC容器

2018-02-24 15:51 更新

看Laravel的IoC容器文檔只是介紹實(shí)例,但是沒(méi)有說(shuō)原理,之前用MVC框架都沒(méi)有在意這個(gè)概念,無(wú)意中在phalcon的文檔中看到這個(gè)詳細(xì)的介紹,感覺(jué)豁然開(kāi)朗,復(fù)制粘貼過(guò)來(lái),主要是好久沒(méi)有寫(xiě)東西了,現(xiàn)在確實(shí)很懶變得!

首先,我們假設(shè),我們要開(kāi)發(fā)一個(gè)組件命名為SomeComponent。這個(gè)組件中現(xiàn)在將要注入一個(gè)數(shù)據(jù)庫(kù)連接。

在這個(gè)例子中,數(shù)據(jù)庫(kù)連接在component中被創(chuàng)建,這種方法是不切實(shí)際的,這樣做的話,我們將不能改變數(shù)據(jù)庫(kù)連接參數(shù)及數(shù)據(jù)庫(kù)類型等一些參數(shù)。

<?php

class SomeComponent
{

    /**
     * The instantiation of the connection is hardcoded inside
     * the component so is difficult to replace it externally
     * or change its behavior
     */
    public function someDbTask()
    {
        $connection = new Connection(array(
            "host" => "localhost",
            "username" => "root",
            "password" => "secret",
            "dbname" => "invo"
        ));

        // ...
    }

}

$some = new SomeComponent();
$some->someDbTask();

為了解決上面所說(shuō)的問(wèn)題,我們需要在使用前創(chuàng)建一個(gè)外部連接,并注入到容器中。就目前而言,這看起來(lái)是一個(gè)很好的解決方案:

<?php

class SomeComponent
{

    protected $_connection;

    /**
     * Sets the connection externally
     */
    public function setConnection($connection)
    {
        $this->_connection = $connection;
    }

    public function someDbTask()
    {
        $connection = $this->_connection;

        // ...
    }

}

$some = new SomeComponent();

//Create the connection
$connection = new Connection(array(
    "host" => "localhost",
    "username" => "root",
    "password" => "secret",
    "dbname" => "invo"
));

//Inject the connection in the component
$some->setConnection($connection);

$some->someDbTask();

現(xiàn)在我們來(lái)考慮一個(gè)問(wèn)題,我們?cè)趹?yīng)用程序中的不同地方使用此組件,將多次創(chuàng)建數(shù)據(jù)庫(kù)連接。使用一種類似全局注冊(cè)表的方式,從這獲得一個(gè)數(shù)據(jù)庫(kù)連接實(shí)例,而不是使用一次就創(chuàng)建一次。

<?php

class Registry
{

    /**
     * Returns the connection
     */
    public static function getConnection()
    {
       return new Connection(array(
            "host" => "localhost",
            "username" => "root",
            "password" => "secret",
            "dbname" => "invo"
        ));
    }

}

class SomeComponent
{

    protected $_connection;

    /**
     * Sets the connection externally
     */
    public function setConnection($connection){
        $this->_connection = $connection;
    }

    public function someDbTask()
    {
        $connection = $this->_connection;

        // ...
    }

}

$some = new SomeComponent();

//Pass the connection defined in the registry
$some->setConnection(Registry::getConnection());

$some->someDbTask();

現(xiàn)在,讓我們來(lái)想像一下,我們必須在組件中實(shí)現(xiàn)兩個(gè)方法,首先需要?jiǎng)?chuàng)建一個(gè)新的數(shù)據(jù)庫(kù)連接,第二個(gè)總是獲得一個(gè)共享連接:

<?php

class Registry
{

    protected static $_connection;

    /**
     * Creates a connection
     */
    protected static function _createConnection()
    {
        return new Connection(array(
            "host" => "localhost",
            "username" => "root",
            "password" => "secret",
            "dbname" => "invo"
        ));
    }

    /**
     * Creates a connection only once and returns it
     */
    public static function getSharedConnection()
    {
        if (self::$_connection===null){
            $connection = self::_createConnection();
            self::$_connection = $connection;
        }
        return self::$_connection;
    }

    /**
     * Always returns a new connection
     */
    public static function getNewConnection()
    {
        return self::_createConnection();
    }

}

class SomeComponent
{

    protected $_connection;

    /**
     * Sets the connection externally
     */
    public function setConnection($connection){
        $this->_connection = $connection;
    }

    /**
     * This method always needs the shared connection
     */
    public function someDbTask()
    {
        $connection = $this->_connection;

        // ...
    }

    /**
     * This method always needs a new connection
     */
    public function someOtherDbTask($connection)
    {

    }

}

$some = new SomeComponent();

//This injects the shared connection
$some->setConnection(Registry::getSharedConnection());

$some->someDbTask();

//Here, we always pass a new connection as parameter
$some->someOtherDbTask(Registry::getConnection());

到此為止,我們已經(jīng)看到了如何使用依賴注入解決我們的問(wèn)題。不是在代碼內(nèi)部創(chuàng)建依賴關(guān)系,而是讓其作為一個(gè)參數(shù)傳遞,這使得我們的程序更容易維護(hù),降低程序代碼的耦合度,實(shí)現(xiàn)一種松耦合。但是從長(zhǎng)遠(yuǎn)來(lái)看,這種形式的依賴注入也有一些缺點(diǎn)。

例如,如果組件中有較多的依賴關(guān)系,我們需要?jiǎng)?chuàng)建多個(gè)setter方法傳遞,或創(chuàng)建構(gòu)造函數(shù)進(jìn)行傳遞。另外,每次使用組件時(shí),都需要?jiǎng)?chuàng)建依賴組件,使代碼維護(hù)不太易,我們編寫(xiě)的代碼可能像這樣:

<?php

//Create the dependencies or retrieve them from the registry
$connection = new Connection();
$session = new Session();
$fileSystem = new FileSystem();
$filter = new Filter();
$selector = new Selector();

//Pass them as constructor parameters
$some = new SomeComponent($connection, $session, $fileSystem, $filter, $selector);

// ... or using setters

$some->setConnection($connection);
$some->setSession($session);
$some->setFileSystem($fileSystem);
$some->setFilter($filter);
$some->setSelector($selector);

我想,我們不得不在應(yīng)用程序的許多地方創(chuàng)建這個(gè)對(duì)象。如果你不需要依賴的組件后,我們又要去代碼注入部分移除構(gòu)造函數(shù)中的參數(shù)或者是setter方法。為了解決這個(gè)問(wèn)題,我們?cè)俅畏祷厝ナ褂靡粋€(gè)全局注冊(cè)表來(lái)創(chuàng)建組件。但是,在創(chuàng)建對(duì)象之前,它增加了一個(gè)新的抽象層:

<?php

class SomeComponent
{

    // ...

    /**
     * Define a factory method to create SomeComponent instances injecting its dependencies
     */
    public static function factory()
    {

        $connection = new Connection();
        $session = new Session();
        $fileSystem = new FileSystem();
        $filter = new Filter();
        $selector = new Selector();

        return new self($connection, $session, $fileSystem, $filter, $selector);
    }

}

這一刻,我們好像回到了問(wèn)題的開(kāi)始,我們正在創(chuàng)建組件內(nèi)部的依賴,我們每次都在修改以及找尋一種解決問(wèn)題的辦法,但這都不是很好的做法。

一種實(shí)用和優(yōu)雅的來(lái)解決這些問(wèn)題,是使用容器的依賴注入,像我們?cè)谇懊婵吹降?,容器作為全局注?cè)表,使用容器的依賴注入做為一種橋梁來(lái)解決依賴可以使我們的代碼耦合度更低,很好的降低了組件的復(fù)雜性:

<?php

class SomeComponent
{

    protected $_di;

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

    public function someDbTask()
    {

        // Get the connection service
        // Always returns a new connection
        $connection = $this->_di->get('db');

    }

    public function someOtherDbTask()
    {

        // Get a shared connection service,
        // this will return the same connection everytime
        $connection = $this->_di->getShared('db');

        //This method also requires a input filtering service
        $filter = $this->_db->get('filter');

    }

}

$di = new Phalcon\DI();

//Register a "db" service in the container
$di->set('db', function(){
    return new Connection(array(
        "host" => "localhost",
        "username" => "root",
        "password" => "secret",
        "dbname" => "invo"
    ));
});

//Register a "filter" service in the container
$di->set('filter', function(){
    return new Filter();
});

//Register a "session" service in the container
$di->set('session', function(){
    return new Session();
});

//Pass the service container as unique parameter
$some = new SomeComponent($di);

$some->someTask();

現(xiàn)在,該組件只有訪問(wèn)某種service的時(shí)候才需要它,如果它不需要,它甚至不初始化,以節(jié)約資源。該組件是高度解耦。他們的行為,或者說(shuō)他們的任何其他方面都不會(huì)影響到組件本身。
我們的實(shí)現(xiàn)辦法?

Phalcon\DI 是一個(gè)實(shí)現(xiàn)了服務(wù)的依賴注入功能的組件,它本身也是一個(gè)容器。

由于Phalcon高度解耦,Phalcon\DI 是框架用來(lái)集成其他組件的必不可少的部分,開(kāi)發(fā)人員也可以使用這個(gè)組件依賴注入和管理應(yīng)用程序中不同類文件的實(shí)例。

基本上,這個(gè)組件實(shí)現(xiàn)了 Inversion of Control 模式。基于此,對(duì)象不再以構(gòu)造函數(shù)接收參數(shù)或者使用setter的方式來(lái)實(shí)現(xiàn)注入,而是直接請(qǐng)求服務(wù)的依賴注入。這就大大降低了整體程序的復(fù)雜性,因?yàn)橹挥幸粋€(gè)方法用以獲得所需要的一個(gè)組件的依賴關(guān)系。

此外,這種模式增強(qiáng)了代碼的可測(cè)試性,從而使它不容易出錯(cuò)。
在容器中注冊(cè)服務(wù)?

框架本身或開(kāi)發(fā)人員都可以注冊(cè)服務(wù)。當(dāng)一個(gè)組件A要求調(diào)用組件B(或它的類的一個(gè)實(shí)例),可以從容器中請(qǐng)求調(diào)用組件B,而不是創(chuàng)建組件B的一個(gè)實(shí)例。

這種工作方式為我們提供了許多優(yōu)點(diǎn):

我們可以更換一個(gè)組件,從他們本身或者第三方輕松創(chuàng)建。
在組件發(fā)布之前,我們可以充分的控制對(duì)象的初始化,并對(duì)對(duì)象進(jìn)行各種設(shè)置。
我們可以使用統(tǒng)一的方式從組件得到一個(gè)結(jié)構(gòu)化的全局實(shí)例

服務(wù)可以通過(guò)以下幾種方式注入到容器:

<?php

//Create the Dependency Injector Container
$di = new Phalcon\DI();

//By its class name
$di->set("request", 'Phalcon\Http\Request');

//Using an anonymous function, the instance will lazy loaded
$di->set("request", function(){
    return new Phalcon\Http\Request();
});

//Registering directly an instance
$di->set("request", new Phalcon\Http\Request());

//Using an array definition
$di->set("request", array(
    "className" => 'Phalcon\Http\Request'
));

在上面的例子中,當(dāng)向框架請(qǐng)求訪問(wèn)一個(gè)請(qǐng)求數(shù)據(jù)時(shí),它將首先確定容器中是否存在這個(gè)”reqeust”名稱的服務(wù)。

容器會(huì)反回一個(gè)請(qǐng)求數(shù)據(jù)的實(shí)例,開(kāi)發(fā)人員最終得到他們想要的組件。

在上面示例中的每一種方法都有優(yōu)缺點(diǎn),具體使用哪一種,由開(kāi)發(fā)過(guò)程中的特定場(chǎng)景來(lái)決定的。

用一個(gè)字符串來(lái)設(shè)定一個(gè)服務(wù)非常簡(jiǎn)單,但缺少靈活性。設(shè)置服務(wù)時(shí),使用數(shù)組則提供了更多的靈活性,而且可以使用較復(fù)雜的代碼。lambda函數(shù)是兩者之間一個(gè)很好的平衡,但也可能導(dǎo)致更多的維護(hù)管理成本。

Phalcon\DI 提供服務(wù)的延遲加載。除非開(kāi)發(fā)人員在注入服務(wù)的時(shí)候直接實(shí)例化一個(gè)對(duì)象,然后存存儲(chǔ)到容器中。在容器中,通過(guò)數(shù)組,字符串等方式存儲(chǔ)的服務(wù)都將被延遲加載,即只有在請(qǐng)求對(duì)象的時(shí)候才被初始化。

<?php

//Register a service "db" with a class name and its parameters
$di->set("db", array(
    "className" => "Phalcon\Db\Adapter\Pdo\Mysql",
    "parameters" => array(
          "parameter" => array(
               "host" => "localhost",
               "username" => "root",
               "password" => "secret",
               "dbname" => "blog"
          )
    )
));

//Using an anonymous function
$di->set("db", function(){
    return new Phalcon\Db\Adapter\Pdo\Mysql(array(
         "host" => "localhost",
         "username" => "root",
         "password" => "secret",
         "dbname" => "blog"
    ));
});

以上這兩種服務(wù)的注冊(cè)方式產(chǎn)生相同的結(jié)果。然后,通過(guò)數(shù)組定義的,在后面需要的時(shí)候,你可以修改服務(wù)參數(shù):

<?php

$di->setParameter("db", 0, array(
    "host" => "localhost",
    "username" => "root",
    "password" => "secret"
));

從容器中獲得服務(wù)的最簡(jiǎn)單方式就是使用”get”方法,它將從容器中返回一個(gè)新的實(shí)例:

<?php $request = $di->get("request");

或者通過(guò)下面這種魔術(shù)方法的形式調(diào)用:

<?php

$request = $di->getRequest();
//Phalcon\DI 同時(shí)允許服務(wù)重用,為了得到一個(gè)已經(jīng)實(shí)例化過(guò)的服務(wù),可以使用 getShared() 方法的形式來(lái)獲得服務(wù)。

具體的 Phalcon\Http\Request 請(qǐng)求示例:

    <?php
    $request = $di->getShared("request");

參數(shù)還可以在請(qǐng)求的時(shí)候通過(guò)將一個(gè)數(shù)組參數(shù)傳遞給構(gòu)造函數(shù)的方式:

<?php
    $component = $di->get("MyComponent", array("some-parameter", "other"));

原文地址:http://www.yuansir-web.com/?p=1012&preview=true

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)