快速理解Laravel容器(IOC帘腹、DI贰盗、Provider、Contract)

源碼理解思維的提升

分享一些個(gè)人見解阳欲。
Laravel里面的某些概念童太,就像魔術(shù)一樣,看起來很厲害胸完,當(dāng)知道魔術(shù)怎么變的书释,就會(huì)認(rèn)為也不過如此。所以不必感覺Laravel里有些概念難以理解赊窥。

應(yīng)當(dāng)拋除被框架約束思維的枷鎖爆惧,用PHP設(shè)計(jì)的角度去思考,關(guān)注大概锨能,而不是在在框架層面逐行磨嘰扯再。畢竟源碼那么多芍耘,越是底層變量越多,越抽象熄阻,頻繁的調(diào)用和變量指向斋竞,看到天亮也看不明白。

PHP設(shè)計(jì)的角度去思考怎么理解:
對于Laravel源碼秃殉,代碼很優(yōu)雅坝初,很工程化,很正規(guī)钾军,方便擴(kuò)展鳄袍,這是優(yōu)點(diǎn),壞處就是抽象吏恭,好比垃圾桶里的垃圾都要擺放好拗小,太過于工程化的設(shè)計(jì),會(huì)給寫松散業(yè)務(wù)邏輯的開發(fā)者帶來困惑樱哼。
舉個(gè)例子哀九,Laravel里面的很多契約,好多都是一個(gè)空interface搅幅,放到了vendor下阅束,真的是可要可不要,也確實(shí)有不少人說泰勒·奧特威爾就是炫技盏筐。
所以遲早要被繞暈围俘,必須拋開Laravel里面的各種細(xì)節(jié)砸讳,用不需要太工程化PHP代碼去嘗試實(shí)現(xiàn)它琢融,實(shí)現(xiàn)的過程中會(huì)遇到各種優(yōu)化或者是問題,然后逐步優(yōu)化簿寂。

被框架約束思維的枷鎖怎么理解:
框架發(fā)展了這么久漾抬,源碼的累加,不是讓從頭看的常遂,而是遇到了一類問題纳令,需要追加代碼,是一個(gè)演進(jìn)的過程克胳,通過出現(xiàn)的問題或要優(yōu)化的需求作為驅(qū)動(dòng)來實(shí)現(xiàn)代碼(書寫順序)平绩,而不是通過代碼的作用反推解決的問題(反向反了很難看懂源碼,看不懂干啥的漠另,原因就是這里)捏雌,換句話說,1+1=?是問題笆搓,2是結(jié)果性湿。方向反了只有結(jié)果2纬傲,怎么推理出問題是1+1,還是2+0肤频,既然不知道問題叹括,又怎么知道2的意義是啥,那個(gè)地方要用宵荒?

易經(jīng)思維:像各國人描述烏龜汁雷,得學(xué)很長時(shí)間的各國語言(源碼),隨手畫一個(gè)烏龜(思維)骇扇,全世界的人多能看懂摔竿。
要發(fā)掘的不是源碼這樣寫我怎么看懂,而是這樣寫解決了什么問題少孝。

通俗的演進(jìn)示例

第1步:直接上第一版代碼继低,Test類實(shí)現(xiàn)查詢功能,于是調(diào)用了MySQL類的select方法稍走。

class MySQL {
    public function select() {
        echo '執(zhí)行查詢操作';
    }
}


class Test {
    private $driver;
    public function __construct() {
        $this->driver = new MySQL();
    }

    public function search() {
        return $this->driver->select();
    }
}

$crud = new Test();
$crud->search();

第2步:但是如果以后有了Oracle袁翁,PostgreSQL怎么辦?婿脸,代碼內(nèi)部的依賴寫死了粱胜。
所以類的內(nèi)部要寫活,將內(nèi)部的依賴狐树,反轉(zhuǎn)到外邊焙压,控制權(quán)由類的外部控制,通過構(gòu)造方法傳參實(shí)現(xiàn)抑钟,這就是控制反轉(zhuǎn)涯曲,方便代碼解耦。

<?php

class MySQL {
    public function select() {
        echo '執(zhí)行查詢操作';
    }
}


class Test {
    private $driver;
    public function __construct($driver) {
        $this->driver = $driver;
    }

    public function search() {
        return $this->driver->select();
    }
}

$crud = new Test(new MySQL);
$crud->search();

第3步:但是隨著項(xiàng)目的復(fù)雜在塔,類越來越多幻件,對象到處都是,得有一個(gè)管事的領(lǐng)導(dǎo)人蛔溃,進(jìn)行統(tǒng)一管理绰沥,于是容器出現(xiàn)了。
容器至少需要兩個(gè)方法贺待,bind和make徽曲,bind用于存儲(chǔ),相當(dāng)于領(lǐng)導(dǎo)人管轄的地域麸塞,分配一塊地區(qū)秃臣,讓這些容器有地方生存。make顧名思義就是制造喘垂,創(chuàng)建出來的這些容器(就是實(shí)例化的過程)讓他們做事甜刻。
bind方法一般不會(huì)直接實(shí)例化對象绍撞,因?yàn)榭赡苡貌簧希谴a流程走到哪里了得院,存是得存起來傻铣,防止后期用得上,這很好理解祥绞,就好比Laravel的Cache模塊非洲,不是每次請求都一定能用得上,但是它仍舊會(huì)被預(yù)先加載蜕径。

class Container {
    private $container = [];

    public function bind($name, $class) {
        return $this->container[$name] = $class;
    }

    public function make($name) {
        $class = $this->container[$name] ?? null;
        if(! $class) {
            return null;
        }

        return new $class();
    }
}

第4步两踏,整合到第2步的代碼當(dāng)中。
看起來簡單東西搞復(fù)雜了兜喻,確實(shí)梦染。但是框架中,對于大量的類和對象的管理卻很有用朴皆,結(jié)合框架的反射帕识,以及其它機(jī)制,是能夠讓類的管理變的更優(yōu)雅的遂铡,
沒有容器情況下的例子:
要狗肉賬肮疗,張三問李四要債,李四說債務(wù)轉(zhuǎn)移給王五了去問王五要扒接,王五說債務(wù)轉(zhuǎn)移給趙六了你去問他要伪货,彼此踢皮球的環(huán)節(jié)耦合度太高,互相依賴钾怔。


image.png

有容器情況下的例子:
相當(dāng)于直接起訴到法院碱呼,一步到位,不管你是誰蒂教。我通過法院的管事人巍举,去解決問題脆荷。


image.png
<?php

class MySQL {
    public function select() {
        echo '執(zhí)行查詢操作';
    }
}


class Test {
    private $driver;
    public function __construct($driver) {
        $this->driver = $driver;
    }

    public function search() {
        return $this->driver->select();
    }
}


class Container {
    private $container = [];

    public function bind($name, $class) {
        return $this->container[$name] = $class;
    }

    public function make($name) {
        $class = $this->container[$name] ?? null;
        if(! $class) {
            return null;
        }

        return new $class();
    }
}

$container = new Container();
$container->bind('MySQL', MySQL::class);


$crud = new Test($container->make('MySQL'));
$crud->search();

Laravel容器

laravel容器的源碼在vendor/laravel/framework/src/Illuminate/Container/Container.php
Laravel核心概念凝垛,類比成一個(gè)存放各類對象的數(shù)組,貫穿了整個(gè)Laravel流程蜓谋,用于降低耦合度梦皮,管理并存儲(chǔ)各模塊的類與對象。
一個(gè)框架提供了很多模塊桃焕,就需要很多對象剑肯,這些對象需要統(tǒng)一管理,自動(dòng)實(shí)例化观堂,以及類類型的形參自動(dòng)實(shí)例化的反射機(jī)制让网,于是有了容器呀忧。

IOC(控制反轉(zhuǎn))

類內(nèi)部的依賴,反轉(zhuǎn)到類外邊溃睹,控制權(quán)由類的外部控制而账,通過構(gòu)造方法傳參實(shí)現(xiàn),這就是控制反轉(zhuǎn)因篇,方便代碼解耦泞辐。
上文示例有說明。

DI(依賴注入)

依賴注入是控制反轉(zhuǎn)的一種實(shí)現(xiàn)方式
依賴注入函數(shù)內(nèi)部傳參竞滓,有助于提高代碼的模塊化咐吼、可測試性和靈活性,通俗講就是按(開發(fā)者)需加載商佑。
如下锯茄,UserController依賴于UserService類。在控制器的構(gòu)造函數(shù)中注入了 UserService茶没,而不是在 UserController 中實(shí)例化UserService的實(shí)例撇吞。Laravel的服務(wù)容器的反射機(jī)制會(huì)自動(dòng)解析這個(gè)依賴關(guān)系。

class UserController extends Controller {
    protected $userService;
    public function __construct(UserService $userService) {
        $this->userService = $userService;
    }
}

Contract(契約)

看了容器的源碼礁叔,發(fā)現(xiàn)有用到牍颈,順便提一嘴。
聽起來高大上琅关,移除Laravel框架高大上的思維枷鎖煮岁,也就一堆接口醒颖,用于規(guī)范化代碼匠楚,實(shí)現(xiàn)大體布局,子類用它實(shí)現(xiàn)細(xì)節(jié)系任,沒什么神奇的高科技新症。

Provider(服務(wù)提供者)

多個(gè)服務(wù)提供者組成一個(gè)容器步氏,新建的provider需要再config/app.php中聲明。
用于注冊應(yīng)用程序的服務(wù)徒爹、綁定依賴關(guān)系以及其它初始化操作荚醒,真用到的時(shí)候就去實(shí)現(xiàn),沒那么嚴(yán)謹(jǐn)隆嗅。
先調(diào)用register方法界阁,然后會(huì)去調(diào)用boot方法。

這個(gè)在安裝某些插件的時(shí)候回去用這個(gè)胖喳,composer包里的代碼泡躯,不足以支撐當(dāng)前的應(yīng)用場景,所以需要做一些配置,然后就用到了Provider较剃。

app()咕别、resolve()

我看到前公司技術(shù)老大經(jīng)常這樣用,以我目前的認(rèn)知來看写穴,這和直接用命名空間的邏輯去調(diào)用一個(gè)類沒什么區(qū)別顷级。

  • app(); 返回服務(wù)容器實(shí)例,參數(shù)可傳遞類名,表示調(diào)用那個(gè)類确垫。
  • resolve();app()的別名弓颈, 函數(shù)使用服務(wù)容器解析給定名稱的類或接口的實(shí)例,參數(shù)可傳遞類名删掀,表示調(diào)用那個(gè)類翔冀。

擴(kuò)展閱讀

淺談PHP框架中類成員方法的類類型形參是怎么利用ReflectionClass反射類自動(dòng)實(shí)例化的(應(yīng)該是全網(wǎng)首發(fā))

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市披泪,隨后出現(xiàn)的幾起案子纤子,更是在濱河造成了極大的恐慌,老刑警劉巖款票,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件控硼,死亡現(xiàn)場離奇詭異,居然都是意外死亡艾少,警方通過查閱死者的電腦和手機(jī)卡乾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缚够,“玉大人幔妨,你說我怎么就攤上這事〉危” “怎么了误堡?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長雏吭。 經(jīng)常有香客問我锁施,道長,這世上最難降的妖魔是什么杖们? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任悉抵,我火速辦了婚禮,結(jié)果婚禮上胀莹,老公的妹妹穿的比我還像新娘基跑。我一直安慰自己婚温,他們只是感情好描焰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般荆秦。 火紅的嫁衣襯著肌膚如雪篱竭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天步绸,我揣著相機(jī)與錄音掺逼,去河邊找鬼。 笑死瓤介,一個(gè)胖子當(dāng)著我的面吹牛吕喘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刑桑,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼氯质,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了祠斧?” 一聲冷哼從身側(cè)響起闻察,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎琢锋,沒想到半個(gè)月后辕漂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吴超,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年钉嘹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲸阻。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡隧期,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赘娄,到底是詐尸還是另有隱情仆潮,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布遣臼,位于F島的核電站性置,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏揍堰。R本人自食惡果不足惜鹏浅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望屏歹。 院中可真熱鬧隐砸,春花似錦、人聲如沸蝙眶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至式塌,卻和暖如春博敬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背峰尝。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國打工偏窝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人武学。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓祭往,卻偏偏與公主長得像,于是被迫代替她去往敵國和親火窒。 傳聞我的和親對象是個(gè)殘疾皇子链沼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容