成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Laravel 服務(wù)容器實(shí)現(xiàn)原理

wupengyu / 1627人閱讀

摘要:框架中就是使用服務(wù)容器來(lái)實(shí)現(xiàn)控制反轉(zhuǎn)和依賴(lài)注入。容器依賴(lài)注入的實(shí)現(xiàn)實(shí)現(xiàn)原理需要了解的知識(shí)點(diǎn)閉包匿名函數(shù)匿名函數(shù),也叫閉包函數(shù),允許臨時(shí)創(chuàng)建一個(gè)沒(méi)有指定名稱(chēng)的函數(shù)反射以上版本具有完整的反射,添加了對(duì)類(lèi)接口函數(shù)方法和擴(kuò)展進(jìn)行反向工程的能力。

前言

通過(guò)實(shí)現(xiàn)laravel 框架功能,以便深入理解laravel框架的先進(jìn)思想。

什么是服務(wù)容器

服務(wù)容器是用來(lái)管理類(lèi)依賴(lài)與運(yùn)行依賴(lài)注入的工具。Laravel框架中就是使用服務(wù)容器來(lái)實(shí)現(xiàn) 控制反轉(zhuǎn) 依賴(lài)注入 。

什么是控制反轉(zhuǎn)(IoC)和依賴(lài)注入(DI)

控制反轉(zhuǎn)(IoC) 就是說(shuō)把創(chuàng)建對(duì)象的 控制權(quán) 進(jìn)行轉(zhuǎn)移,以前創(chuàng)建對(duì)象的主動(dòng)權(quán)和創(chuàng)建時(shí)機(jī)是由自己把控的,而現(xiàn)在這種權(quán)力轉(zhuǎn)移到第三方,也就是 Laravel 中的容器。

依賴(lài)注入(DI)則是幫助容器實(shí)現(xiàn)在運(yùn)行中動(dòng)態(tài)的為對(duì)象提供提依賴(lài)的資源。

概念容易不太容易讓人理解,舉個(gè)栗子:

//我們構(gòu)建一個(gè)人的類(lèi)和一個(gè)狗的類(lèi)
 class People
{
    public $dog = null;

    public function __construct()
    {
        $this->dog = new Dog();
    }

    public function putDog(){
        return $this->dog->dogCall();
    }

}

class Dog{
    public function dogCall(){
        return "汪汪汪";
    }
}

這個(gè)人在遛狗,突然遇到了死對(duì)頭,他于是放狗咬人

$people = new People();
$people->putDog();

在這個(gè)操作中,people類(lèi)要執(zhí)行 putDog() 這個(gè)方法,需要依賴(lài)Dog類(lèi),一般我們像上面一樣,在people中利用構(gòu)造函數(shù)來(lái)添加這個(gè)Dog依賴(lài)。如果使用控制反轉(zhuǎn) 依賴(lài)注入則是這個(gè)樣子

class People
{
    public $dog = null;

    public function __construct(Dog $Dog)
    {
        $this->dog = $dog;
    }

    public function putDog(){
        return $this->dog->dogCall();
    }

}

People類(lèi)通過(guò)構(gòu)造參數(shù)聲明自己需要的 依賴(lài)類(lèi),由容器自動(dòng)注入。這樣就實(shí)現(xiàn)了程序的有效解耦,好處在這就不多說(shuō)了。

Laravel容器依賴(lài)注入的實(shí)現(xiàn)
實(shí)現(xiàn)原理需要了解的知識(shí)點(diǎn):

閉包(匿名函數(shù)):

匿名函數(shù)(Anonymous functions),也叫閉包函數(shù)(closures),允許 臨時(shí)創(chuàng)建一個(gè)沒(méi)有指定名稱(chēng)的函數(shù)

反射:PHP 5 以上版本具有完整的反射 API,添加了對(duì)類(lèi)、接口、函數(shù)、方法和擴(kuò)展進(jìn)行反向工程的能力。 此外,反射 API 提供了方法來(lái)取出函數(shù)、類(lèi)和方法中的文檔注釋

理解了閉包和反射的基本用法我們來(lái)看Laravel中是怎么實(shí)現(xiàn)容器的,下面代碼是我對(duì)laravel框架容器部分代碼的簡(jiǎn)化核心版:
lass Container
{
    /**
     *  容器綁定,用來(lái)裝提供的實(shí)例或者 提供實(shí)例的回調(diào)函數(shù)
     * @var array
     */
    public $building = [];

    /**
     * 注冊(cè)一個(gè)綁定到容器
     */
    public function bind($abstract, $concrete = null, $shared = false)
    {
        if(is_null($concrete)){
            $concrete = $abstract;
        }

        if(!$concrete instanceOf Closure){
            $concrete = $this->getClosure($abstract, $concrete);
        }

        $this->building[$abstract] =  compact("concrete", "shared");
    }

    //注冊(cè)一個(gè)共享的綁定 單例
    public function singleton($abstract, $concrete, $shared = true){
        $this->bind($abstract, $concrete, $shared);
    }

    /**
     * 默認(rèn)生成實(shí)例的回調(diào)閉包
     *
     * @param $abstract
     * @param $concrete
     * @return Closure
     */
    public function getClosure($abstract, $concrete)
    {
        return function($c) use($abstract, $concrete){
            $method = ($abstract == $concrete)? "build" : "make";

            return $c->$method($concrete);
        };
    }

    /**
     * 生成實(shí)例 
     */
    public function make($abstract)
    {
        $concrete = $this->getConcrete($abstract);

        if($this->isBuildable($concrete, $abstract)){
            $object = $this->build($concrete);
        }else{
            $object = $this->make($concrete);
        }

        return $object;
    }

    /**
     * 獲取綁定的回調(diào)函數(shù)
     */
    public function getConcrete($abstract)
    {
        if(! isset($this->building[$abstract])){
            return $abstract;
        }

        return $this->building[$abstract]["concrete"];
    }

    /**
     * 判斷 是否 可以創(chuàng)建服務(wù)實(shí)體
     */
    public function isBuildable($concrete, $abstract)
    {
        return $concrete === $abstract || $concrete instanceof Closure;
    }

    /**
     * 根據(jù)實(shí)例具體名稱(chēng)實(shí)例具體對(duì)象
     */
    public function build($concrete)
    {
        if($concrete instanceof Closure){
            return $concrete($this);
        }

        //創(chuàng)建反射對(duì)象
        $reflector = new ReflectionClass($concrete);

        if( ! $reflector->isInstantiable()){
            //拋出異常
            throw new Exception("無(wú)法實(shí)例化");
        }

        $constructor = $reflector->getConstructor();
        if(is_null($constructor)){
            return new $concrete;
        }

        $dependencies = $constructor->getParameters();
        $instance = $this->getDependencies($dependencies);

        return $reflector->newInstanceArgs($instance);

    }

    //通過(guò)反射解決參數(shù)依賴(lài)
    public function getDependencies(array $dependencies)
    {
        $results = [];
        foreach( $dependencies as $dependency ){
            $results[] = is_null($dependency->getClass())
                ?$this->resolvedNonClass($dependency)
                :$this->resolvedClass($dependency);
        }

        return $results;
    }

    //解決一個(gè)沒(méi)有類(lèi)型提示依賴(lài)
    public function resolvedNonClass(ReflectionParameter $parameter)
    {
        if($parameter->isDefaultValueAvailable()){
            return $parameter->getDefaultValue();
        }
        throw new Exception("出錯(cuò)");

    }

    //通過(guò)容器解決依賴(lài)
    public function resolvedClass(ReflectionParameter $parameter)
    {
        return $this->make($parameter->getClass()->name);

    }

}
容器的工作流程

接著上面遛狗的例子:

//實(shí)例化容器類(lèi)
$app =  new Container();
//向容器中填充Dog
$app->bind("Dog","AppDog");
//填充People
$app->bind("People", "AppPeople");
//通過(guò)容器實(shí)現(xiàn)依賴(lài)注入,完成類(lèi)的實(shí)例化;
$people = $app->make("People");
//調(diào)用方法
echo $people->putDog();

上面示例中我們先實(shí)例化容器類(lèi),然后使用 bind() 方法 綁定接口和 生成相應(yīng)的實(shí)例的閉包函數(shù)。然后使用 make() 函數(shù)生成實(shí)例對(duì)象,在 make() 中會(huì)調(diào)用 isBuildable($concrete, $abstract) 來(lái)判斷 給定的服務(wù)實(shí)體( $concrete 參數(shù))是否可以創(chuàng)建,可以創(chuàng)建 就會(huì)調(diào)用 build($concrete) 函數(shù) , build($concrete) 函數(shù)會(huì)判斷傳的參數(shù)是 是 閉包 還是 具體類(lèi)名 ,如果是閉包則直接運(yùn)行,如果是具體類(lèi)名的話(huà),則通過(guò)反射獲取該類(lèi)的構(gòu)造函數(shù)所需的依賴(lài),完成實(shí)例化。

重點(diǎn)理解 下面這幾個(gè)函數(shù)中 反射的用法,應(yīng)該就很好理解了

build($concrete)
getDependencies(array $dependencies)
resolvedNonClass(ReflectionParameter $parameter)
resolvedClass(ReflectionParameter $parameter)
最后

IoC 理解起來(lái)是有點(diǎn)難度,可能文中描述讓你感覺(jué)不是很清楚,可以將文中代碼 在php中用debug觀察 運(yùn)行狀態(tài)。

理解了容器的具體實(shí)現(xiàn)原理,再去看Laravel中的相關(guān)實(shí)現(xiàn),就會(huì)感覺(jué)豁然開(kāi)朗。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/22623.html

相關(guān)文章

  • 深入剖析 Laravel 服務(wù)容器

    摘要:劃下重點(diǎn),服務(wù)容器是用于管理類(lèi)的依賴(lài)和執(zhí)行依賴(lài)注入的工具。類(lèi)的實(shí)例化及其依賴(lài)的注入,完全由服務(wù)容器自動(dòng)的去完成。 本文首發(fā)于 深入剖析 Laravel 服務(wù)容器,轉(zhuǎn)載請(qǐng)注明出處。喜歡的朋友不要吝嗇你們的贊同,謝謝。 之前在 深度挖掘 Laravel 生命周期 一文中,我們有去探究 Laravel 究竟是如何接收 HTTP 請(qǐng)求,又是如何生成響應(yīng)并最終呈現(xiàn)給用戶(hù)的工作原理。 本章將帶領(lǐng)大...

    abson 評(píng)論0 收藏0
  • 深入剖析 Laravel 服務(wù)提供者實(shí)現(xiàn)原理

    摘要:服務(wù)提供者啟動(dòng)原理之前我們有學(xué)習(xí)深度挖掘生命周期和深入剖析服務(wù)容器,今天我們將學(xué)習(xí)服務(wù)提供者。的所有核心服務(wù)都是通過(guò)服務(wù)提供者進(jìn)行引導(dǎo)啟動(dòng)的,所以想深入了解那么研究服務(wù)提供者的原理是個(gè)繞不開(kāi)的話(huà)題。 本文首發(fā)于 深入剖析 Laravel 服務(wù)提供者實(shí)現(xiàn)原理,轉(zhuǎn)載請(qǐng)注明出處。 今天我們將學(xué)習(xí) Laravel 框架另外一個(gè)核心內(nèi)容「服務(wù)提供者(Service Provider)」。服務(wù)提供...

    yeooo 評(píng)論0 收藏0
  • PHPer、Laravel 面試可能會(huì)遇到的問(wèn)題及答案

    摘要:如何實(shí)現(xiàn)持久化持久化,將在內(nèi)存中的的狀態(tài)保存到硬盤(pán)中,相當(dāng)于備份數(shù)據(jù)庫(kù)狀態(tài)。相當(dāng)于備份數(shù)據(jù)庫(kù)接收到的命令,所有被寫(xiě)入的命令都是以的協(xié)議格式來(lái)保存的。 最近社區(qū)里面有一篇文章引起了最多程序猿的關(guān)注,Laravel、PHPer 面試可能會(huì)遇到的問(wèn)題,看評(píng)論區(qū)不少小伙伴們被難倒,對(duì)于一些問(wèn)題同樣難倒了我(其實(shí)有很多啦),趁著周末有空,又總結(jié)梳理了一遍,順便來(lái)答一波題。由于個(gè)人技術(shù)水平有限,答...

    fanux 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<