一篇文章讓你明白Laravel服務(wù)容器

DI

DI就是常說的依賴注入伴挚,那么究竟什么是依賴注入呢?

打個比方灾炭,電腦(非筆記本哈)需要鍵盤和鼠標(biāo)我們才能進(jìn)行操作,這個‘需要’換句話說就是‘依賴’鍵盤和鼠標(biāo)颅眶。

那么蜈出,相應(yīng)的,一個類需要另一個類才能進(jìn)行作業(yè)涛酗,那么這也就是依賴铡原。

看一段代碼:


    class Computer {
        protected $keyboard;
        
        public function __construct() {
            $this->$keyboard = new Keyboard();
        }
    }
    
    這里的Computer類依賴了鍵盤類。

好商叹,既然我們已經(jīng)知道了什么是依賴燕刻,那么什么是注入呢?

我們改造一下上面的代碼:

     class Computer {
        protected $keyboard;
        
        public function __construct(Keyboard $keyboard) {
            $this->$keyboard = $keyboard;
        }
    }
    
    $computer = new Computer(new Keyboard());
    
    
    這里的Computer類依賴注入了Keyboard類剖笙。

關(guān)于依賴注入卵洗,我的理解是:

所需要的類通過參數(shù)的形式傳入的就是依賴注入。

理解了依賴注入弥咪,我們可以接著理解IOC过蹂。

IOC

IOC是什么呢?

中文叫控制反轉(zhuǎn)聚至。啥意思呢酷勺? 這個看明白了DI后就能很容易的理解了。

通過DI我們可以看到扳躬,一個類所需要的依賴類是由我們主動實例化后傳入類中的脆诉。

控制反轉(zhuǎn)和這個有什么關(guān)系呢?

控制反轉(zhuǎn)意思是說將依賴類的控制權(quán)交出去贷币,由主動變?yōu)楸粍印?/p>

看一段laravel代碼:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SessionController extends Controller
{

    public function login(Request $request)
    {
        //這就是IOC击胜,我們不需要主動傳入類了一切由laravel去實現(xiàn)
    }
}

看到這你可能有疑問了,這是怎么實現(xiàn)的呢役纹?

這就是靠服務(wù)容器了潜的,請往下接著看。

服務(wù)容器

看了很多文章字管,我一致認(rèn)為服務(wù)容器就是一種設(shè)計模式啰挪。

它的目的就是解耦依賴信不。

它有點類似于我前面說的《享元模式》。區(qū)別在于服務(wù)容器解決了所有依賴的實現(xiàn)抽活。

這里我們再從頭至尾的看一遍锰什,怎么一步步演化出服務(wù)容器。

依然是電腦的例子梭姓,我們知道電腦依賴鍵盤鼠標(biāo)誉尖,可是鍵盤鼠標(biāo)也有很多種呀铡恕。

先看一個最原始的代碼例子:


     class Computer {
        protected $keyboard;
        
        public function __construct($type == null) {
            
            switch($type) {
                case 'common':
                    $this->keyboard = new CommonKeyboard();
                    break;
                case 'awesome':
                    $this->keyboard = new AweSomeKeyboard();
                    break;
                default:
                    $this->keyboard = new Keyboard();
                    break;
            }
          
        }
    }

或許你一眼就看出了問題在哪探熔。

如果我們又要增加一鐘鍵盤烘挫,那我們又得對這個類進(jìn)行修改饮六。這樣下去,這個類會變得龐大且耦合程度過高捉捅。

那么我們可以怎么修改呢虽风?

  • 工廠模式

這樣我們可以避免直接的修改Computer類辜膝。

    簡單工廠
    class Factory {
        
        public static function getInstance($type){
            switch($type) {
                case 'common':
                    $this->keyboard = new CommonKeyboard();
                    break;
                case 'awesome':
                    $this->keyboard = new AweSomeKeyboard();
                    break;
                default:
                    $this->keyboard = new Keyboard();
                    break;
            }
        }
    }
    
    class Computer {
        protected $keyboard;
        
        public function __construct($type == null) {
            $this->keyboard = Factory::getInstance($type);
        }
    }

這樣使用簡單工廠模式后厂抖,我們后續(xù)的修改可以不用對Computer類進(jìn)行操作而只要修改工廠類就行了。這就相當(dāng)于對Computer類進(jìn)行了解耦谭溉。

Computer類雖不在依賴那些鍵盤類了橡卤,但是卻變?yōu)橐蕾嚬S類了碧库。

后續(xù)添加新類型的鍵盤就必須對工廠類進(jìn)行修改嵌灰。

所以這個工廠類還不能很好的滿足要求,我們知道電腦對鍵盤的接口都是一致的迁匠,鍵盤必須實現(xiàn)這一接口才能被電腦識別,那我們對Computer和Keyboard類進(jìn)行修改吠架。

  • DI(依賴注入)
    interface Board {
        public function type();
    }
    
    class CommonBoard implements Board {
        public function type(){
            echo '普通鍵盤';
        }
    }
    
    class MechanicalKeyboard implements Board {
        public function type(){
            echo '機械鍵盤';
        }
    }
    
    class Computer {
        protected $keyboard;
        
        public function __construct (Board $keyboard) {
            $this->keyboard = $keyboard;
        }
    }
    
    $computer = new Computer(new MechanialKeyBoard());
    

可是這樣也有問題,如果我們后續(xù)對這臺電腦使用的鍵盤不滿意要進(jìn)行替換呢魂仍? 我們又回到原點了擦酌,必須去修改傳入的鍵盤類赊舶。

能不能做成可配置的呢?

  • IOC服務(wù)容器(超級工廠)
class Container
{
    protected $binds;

    protected $instances;

    public function bind($abstract, $concrete)
    {
        if ($concrete instanceof Closure) {
            $this->binds[$abstract] = $concrete;
        } else {
            $this->instances[$abstract] = $concrete;
        }
    }

    public function make($abstract, $parameters = [])
    {
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        array_unshift($parameters, $this);

        return call_user_func_array($this->binds[$abstract], $parameters);
    }
}

這就是一個簡單的IOC服務(wù)容器。

這個怎么解決我們上述的問題呢锌唾?

    $container = new Container;
    
    $container->bind('Board', function($container){
        return new CommonBoard;
    });
    
    $container->bind('Computer',function($container,$module){
        return new Computer($container->make($module));
    });
    
    $computer = $container->make('Computer',['Board']);
    

這里生產(chǎn)出來的Computer類就是一個使用普通鍵盤的電腦類了滋捶。

解釋一下代碼:

    bind(name,function($container){
        return new Name;
    })
    
    這里的name和Name之間的關(guān)系是:
    當(dāng)我需要name類的時候你就給我實例化Name類渐排。
    
    make(name)方法是對name進(jìn)行生產(chǎn)返回一個實例亲族。

如果我們要更換鍵盤怎么辦呢霎迫?

    $container->bind('Board', function($container){
        return new MechanicalBoard;
    });
    
    $container->bind('Computer',function($container,$module){
        return new Computer($container->make($module));
    });
    
    $computer = $container->make('Computer',['Board']);

只要對bind綁定的Board類的實現(xiàn)進(jìn)行修改知给,我們就可以很容易替換掉鍵盤了涩赢。這就是一個服務(wù)容器筒扒。

對服務(wù)容器進(jìn)行一個理解:

容器就是一個裝東西的花墩,好比碗。而服務(wù)就是這個碗要裝的飯呀祠肥,菜呀搪柑,等等東西。當(dāng)我們需要飯時,我們就能從這個碗里拿到旬迹。如果你想在飯里加點菜(也就是飯依賴注入了菜)奔垦,我們從碗里直接拿飯就可以了屹耐,而這些依賴都由容器解決了(這也就是控制反轉(zhuǎn))。

我們需要做的就是對提供的服務(wù)進(jìn)行維護(hù)椿猎。

我們看一段真實的在laravel框架上能跑的代碼:

代碼

當(dāng)然laravel框架的服務(wù)容器比這里的要復(fù)雜很多了惶岭,但我們明白了它的使用目的以及使用場景就不難去入手laravel了。

PS: 知乎專欄 '程序邊緣',熱烈歡迎7该摺0丛睢!
個人訂閱號:Buger,為你收集各類學(xué)習(xí)資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筐咧,一起剝皮案震驚了整個濱河市鸯旁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌量蕊,老刑警劉巖铺罢,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異残炮,居然都是意外死亡韭赘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門吉殃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辞居,“玉大人楷怒,你說我怎么就攤上這事蛋勺。” “怎么了鸠删?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵抱完,是天一觀的道長。 經(jīng)常有香客問我刃泡,道長巧娱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任烘贴,我火速辦了婚禮禁添,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘桨踪。我一直安慰自己老翘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著铺峭,像睡著了一般墓怀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卫键,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天傀履,我揣著相機與錄音,去河邊找鬼莉炉。 笑死钓账,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呢袱。 我是一名探鬼主播官扣,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼羞福!你這毒婦竟也來了惕蹄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤治专,失蹤者是張志新(化名)和其女友劉穎卖陵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體张峰,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡泪蔫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了喘批。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撩荣。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖饶深,靈堂內(nèi)的尸體忽然破棺而出餐曹,到底是詐尸還是另有隱情,我是刑警寧澤敌厘,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布台猴,位于F島的核電站,受9級特大地震影響俱两,放射性物質(zhì)發(fā)生泄漏饱狂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一宪彩、第九天 我趴在偏房一處隱蔽的房頂上張望休讳。 院中可真熱鬧,春花似錦尿孔、人聲如沸俊柔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽婆咸。三九已至竹捉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尚骄,已是汗流浹背块差。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留倔丈,地道東北人憨闰。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像需五,于是被迫代替她去往敵國和親鹉动。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

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

  • 容器宏邮,字面上理解就是裝東西的東西泽示。常見的變量、對象屬性等都可以算是容器蜜氨。一個容器能夠裝什么械筛,全部取決于你對該容器的...
    拉風(fēng)的老衲閱讀 427評論 1 3
  • 1.1 spring IoC容器和beans的簡介 Spring 框架的最核心基礎(chǔ)的功能是IoC(控制反轉(zhuǎn))容器,...
    simoscode閱讀 6,721評論 2 22
  • 容器飒炎,字面上理解就是裝東西的東西埋哟。常見的變量、對象屬性等都可以算是容器郎汪。一個容器能夠裝什么赤赊,全部取決于你對該容器的...
    叫我峰兄閱讀 339評論 0 0
  • 我喜歡你是靜默的, 如同飛蛾撲火一般煞赢, 揮動著無力的翅膀抛计, 撲進(jìn)愛你的深淵。 好像我的靈魂已飛離去耕驰, 心靈已被你占...
    余子瀟閱讀 1,092評論 16 25
  • 清水襯綠葉靜幽爷辱,花開倆支蓮并嬌录豺, 一粉一白亭亭立朦肘,各灑芬芳各比高。 緣念修得五千年双饥,相知相伴風(fēng)雨飄媒抠, 同根連心并蒂...
    淺淺是水閱讀 851評論 32 49