能不能舉個例子? 文檔好像很不詳細
對於剛理解
IOC
和
DI
概念的我, 勉強只能看懂
register
方法在做什麼
有人幫忙解釋下嗎
回複內容:
能不能舉個例子? 文檔好像很不詳細
對於剛理解 IOC
和 DI
概念的我, 勉強只能看懂 register
方法在做什麼
有人幫忙解釋下嗎
如果你對 IoC 和 DI 還有點模糊,可以參考如下連結,建議按照如下順序進行閱讀:
1.Laravel 官方文檔中對 Service Container 和 Service Provider 的描述,按照目前的積累的經驗進行初步理解
2.一個形象的 IoC 概述
3.通過簡單的 PHP 代碼描述 IoC
4.IoC 的用途、分類的詳細敘述
最後再回過頭來再參考一下 Service Container 和 Service Provider 文檔,並且查看使用者請求的生命週期概述:Request Lifecycle,基本上都可以非常清晰的理解。
現在有了 IoC 和 Laravel 請求生命週期的基礎,瞭解 ServiceProvider 就不會太難。
ServiceProvider
繼承自 ServiceProvider 的類中一般重寫兩個重要的函數:register 和 boot 方法。
0x0. 突發奇想
有一天我突然想用 Laravel 實現一個程式,通過輸入問題來擷取 SegmentFault 上的答案列錶鏈接,廢話少說上代碼:
class SegmentFault { private $server; public function __construct($server) { $this->server = $server; } /** * Retrieve the answers */ public function answer($question) { return $this->server . $question; }}
回到 Controller,現在來調用 SegmentFault 這個類。你需要手動去執行個體化他嗎?不,Laravel 會自動幫你執行個體化:
public function index(SegmentFault $segmentFault) { return $segmentFault->answer('What is Service Provider in Laravel ?'); }
看來我寶刀未老,加上優美的 Laravel 架構分分鐘搞定,激動的我趕緊重新整理一下頁面:
臣蔔木曹,報錯了,看錯誤提示明顯是沒辦法解析 SegmentFault 的參數,說好的自動依賴注入呢!?
不對,我需要傳入 SegmentFault 的搜尋連結參數(不然 Laravel 怎麼會知道需要構造什麼參數呢),但是這樣子要手動執行個體化。。不就傳個參數嗎,我傳:
public function index() { $segmentFault = new SegmentFault('https://segmentfault.com/search?q='); return $segmentFault->answer('What is Service Provider in Laravel ?'); }
這回沒問題了。
0x1. 開始偷懶
現在我想在其他頁面也提供這個功能,似乎每次都要去執行個體化有點麻煩啊。假如有一天 SegmentFault 換了網域名稱,就要修改十幾個函數......
想想這嚴重的結果,不得不改進這個程式。好,回頭來看 IoC。既然 SegmentFault 這個類執行個體化時需要傳入參數,搜搜文檔,原來還挺簡單的,先建個 ServiceProvider 調教一下:
class SegmentFaultServiceProvider extends ServiceProvider { public function register() { $this->app->bind(SegmentFault::class, function() { return new SegmentFault('https://segmentfault.com/search?q='); }); }}
這樣子一來就把依賴資訊配置好了,Laravel 知道怎麼正確執行個體化這個類了,趕緊改寫程式:
public function index(SegmentFault $segmentFault) { return $segmentFault->answer('What is Service Provider in Laravel ?');}
咦,重新整理網頁還是報錯了!? 哦對了,還需要在 config/app.php 中註冊這個 Provider:
'providers' => [ // ... App\Providers\SegmentFaultServiceProvider::class,]
再重新整理,現在可以正常工作了,So cool !! 我不禁從椅子上跳起來。
0x2. 總結
IoC 是將內部設計的類交給系統去控制,但是有些類在初始化的時候,需要制定特定的參數,或者當你需要將實作類別綁定到某個介面,這時候就必須對這些依賴進行配置,系統才能正確解析並引用。
register
而 register 就是這樣一個地方,你可以在 register 配置類的依賴,綁定實作類別到介面,設定類的別名等等。
boot
而 boot 方法在 register 方法之後調用,這就意味著,你無須擔心在注入某個執行個體的時候,他還沒有被綁定或執行個體化。
例如你建立了 SegmentFault 和 SegmentFaultApi 兩個類,前者依賴與後者,但是在 register 中你不確定那個類先被執行個體化了,那麼你可以在 boot 中再對後者進行引用,因為此時兩個類都已經進行正確的配置。
providers
providers 方法用於消極式載入的 ServiceProvider,比如希望在引用的時候再讓系統去解析那個類,那麼可以設定 $defer 變數為 true 來延遲啟動,節省開銷:
protected $defer = true;
當設定了延遲啟動,需要重寫 providers 函數。當 Laravel 遇到消極式載入的類,只要在每個 ServiceProvider 中的 providers 函數中搜尋制定的引用關鍵字,便可以調用正確 register 函數的解析該類:
public function providers() { return [SegmentFault::class];}
這是筆者的一片文章:PHP Laravel 一個請求的處理過程。(當然因為時間關係還沒有寫完,待續23333
有錯誤的地方希望大牛指正,Thx~
以上。