摘要:在服務(wù)提供者內(nèi)部,這個(gè)工作被稱之為服務(wù)容器綁定,綁定處理由服務(wù)提供者完成。通過(guò)服務(wù)提供者綁定服務(wù)是服務(wù)容器綁定服務(wù)的正確打開(kāi)方式。為了完成注冊(cè)服務(wù)提供者的功能,僅需要將類名加入到配置文件的節(jié)點(diǎn)。此時(shí),僅需簡(jiǎn)單的調(diào)整下服務(wù)提供者中的代碼。
這是一篇翻譯文章,譯文首發(fā)于 Laravel 服務(wù)提供者指南,轉(zhuǎn)載請(qǐng)注明出處。
如果你使用過(guò) Laravel 框架的話,那么,你不可能沒(méi)聽(tīng)說(shuō)過(guò)服務(wù)容器和服務(wù)提供者。事實(shí)上,它們是 Lavavel 框架核心,它們完成 Larvel 應(yīng)用中服務(wù)啟動(dòng)的艱巨任務(wù)。
在這篇文章中,我們將簡(jiǎn)單介紹「服務(wù)容器」,同時(shí)還會(huì)深入講解服務(wù)提供者。本教程還將演示如何在 Laravel 中創(chuàng)建一個(gè)自定義的服務(wù)提供者。另外,如果你需要在 Laravel 中成功使用服務(wù)容器,還需要注冊(cè)它。那么,讓我們開(kāi)始吧。
實(shí)現(xiàn)一個(gè)自定義的服務(wù)提供者,需要實(shí)現(xiàn)兩個(gè)非常重要的方法:boot 和 register 方法。關(guān)于這兩個(gè)方法將在教程最后一個(gè)小節(jié)討論。
在學(xué)習(xí)服務(wù)提供者之前,簡(jiǎn)單介紹一下服務(wù)容器,服務(wù)容器會(huì)在服務(wù)提供者中被經(jīng)常使用。
理解服務(wù)容器和服務(wù)提供者 什么是服務(wù)容器簡(jiǎn)而言之,Laravel 服務(wù)容器 是一個(gè)用于存儲(chǔ)綁定組件的盒子,它還會(huì)為應(yīng)用提供所需的服務(wù)。
Laravel 文檔中描述如下:
Laravel 服務(wù)容器是用于管理類的依賴和執(zhí)行依賴注入的工具 - Laravel 文檔
這樣,當(dāng)我們需要注入一個(gè)內(nèi)置的組件或服務(wù)時(shí),可以在構(gòu)造函數(shù)或方法中使用類型提示功能注入,然后在使用時(shí)從服務(wù)容器中自動(dòng)解析出所需實(shí)例及其依賴!是不是很酷?這個(gè)功能可以讓我們從手動(dòng)管理組件中解脫出來(lái),從而降低系統(tǒng)耦合度。
讓我們看一個(gè)簡(jiǎn)單實(shí)例來(lái)加深理解。
如你所見(jiàn),SomeClass 需要使用 FooBar 實(shí)例。換句話說(shuō)它需要依賴其它組件。Laravel 實(shí)現(xiàn)自動(dòng)注入需要從服務(wù)容器中查找并執(zhí)行注入適當(dāng)?shù)囊蕾嚒?/p>
如果你希望了解 Laravel 是如何知道需要將哪個(gè)組件或服務(wù)綁定到服務(wù)容器中的,答案是通過(guò)服務(wù)提供者實(shí)現(xiàn)的。服務(wù)提供者完成將組件綁定到服務(wù)容器的工作。在服務(wù)提供者內(nèi)部,這個(gè)工作被稱之為服務(wù)容器綁定,綁定處理由服務(wù)提供者完成。
服務(wù)提供者實(shí)現(xiàn)了服務(wù)綁定,綁定處理則由 register 方法完成。
同時(shí),這又會(huì)引入一個(gè)新的問(wèn)題:Laravel 是如何知道有哪些服務(wù)提供者的呢?這個(gè)我們貌似還沒(méi)有討論到吧?我到時(shí)看到,之前有說(shuō) Laravel 會(huì)自動(dòng)的去查找到服務(wù)!朋友,你的問(wèn)題太多了:Laravel 只是一個(gè)框架,它不是一個(gè)超級(jí)英雄,不是么?我們當(dāng)然需要去明確的告知 Laravel 框架我們有哪些服務(wù)提供者。
讓我們來(lái)瞧瞧 config/app.php 配置文件。你會(huì)找到一個(gè)用于 Laravel 應(yīng)用啟動(dòng)過(guò)程中被載入的服務(wù)提供者配置列表。
"providers" => [ /* * Laravel Framework Service Providers... */ IlluminateAuthAuthServiceProvider::class, IlluminateBroadcastingBroadcastServiceProvider::class, IlluminateBusBusServiceProvider::class, IlluminateCacheCacheServiceProvider::class, IlluminateFoundationProvidersConsoleSupportServiceProvider::class, IlluminateCookieCookieServiceProvider::class, IlluminateDatabaseDatabaseServiceProvider::class, IlluminateEncryptionEncryptionServiceProvider::class, IlluminateFilesystemFilesystemServiceProvider::class, IlluminateFoundationProvidersFoundationServiceProvider::class, IlluminateHashingHashServiceProvider::class, IlluminateMailMailServiceProvider::class, IlluminateNotificationsNotificationServiceProvider::class, IlluminatePaginationPaginationServiceProvider::class, IlluminatePipelinePipelineServiceProvider::class, IlluminateQueueQueueServiceProvider::class, IlluminateRedisRedisServiceProvider::class, IlluminateAuthPasswordsPasswordResetServiceProvider::class, IlluminateSessionSessionServiceProvider::class, IlluminateTranslationTranslationServiceProvider::class, IlluminateValidationValidationServiceProvider::class, IlluminateViewViewServiceProvider::class, /* * Package Service Providers... */ LaravelTinkerTinkerServiceProvider::class, /* * Application Service Providers... */ AppProvidersAppServiceProvider::class, AppProvidersAuthServiceProvider::class, // AppProvidersBroadcastServiceProvider::class, AppProvidersEventServiceProvider::class, AppProvidersRouteServiceProvider::class, ],以上就是有關(guān)服務(wù)容器的基本概念。下一節(jié),我們將焦點(diǎn)聚集到服務(wù)提供者這個(gè)核心主題上!
什么是服務(wù)提供者如果說(shuō)服務(wù)容器是提供綁定和依賴注入的的工具,那么 服務(wù)提供者 則是實(shí)現(xiàn)綁定的工具。
讓我們先來(lái)看一個(gè)內(nèi)容提供的服務(wù)提供者服務(wù)來(lái)理解它的運(yùn)行原理。打開(kāi) vender/laravel/framework/src/Illuminate/Cache/CacheServiceProvider.php 文件。
public function register() { $this->app->singleton("cache", function ($app) { return new CacheManager($app); }); $this->app->singleton("cache.store", function ($app) { return $app["cache"]->driver(); }); $this->app->singleton("memcached.connector", function () { return new MemcachedConnector; }); }這里我們需要將重點(diǎn)集中在 register 方法中,這個(gè)方法用于綁定服務(wù)到服務(wù)容器。如你所見(jiàn),這里一共執(zhí)行了三個(gè)服務(wù)的綁定處理:cache、cache.store 和 memcached.connector。
然后,當(dāng)我們需要在 Laravel 中使用 cache 服務(wù)是,服務(wù)容器會(huì)解析出 CacheManager 實(shí)例并返回。也就是說(shuō)我們僅僅是提供了一個(gè)可以從 $this->app 訪問(wèn)的對(duì)應(yīng)關(guān)系表。
通過(guò)服務(wù)提供者綁定服務(wù)是 Laravel 服務(wù)容器綁定服務(wù)的正確打開(kāi)方式。同時(shí)通過(guò)服務(wù)提供者的 register 方法,還有利于理解 Laravel 服務(wù)容器是如何管理所有的服務(wù)的。我們之前提到過(guò),通過(guò)從 config/app.php 配置文件中讀取服務(wù)提供者配置列表,從將所有服務(wù)注冊(cè)服務(wù)容器中。
以上,就是服務(wù)提供者和它的故事。下一節(jié),我們會(huì)學(xué)習(xí)如何創(chuàng)建一個(gè)服務(wù)提供者來(lái)實(shí)現(xiàn)將自己的服務(wù)注冊(cè)到 Laravel 服務(wù)容器。
自定義服務(wù)提供者Laravel 已經(jīng)內(nèi)置了一個(gè)用于創(chuàng)建服務(wù)提供者的 artisan 命令來(lái)簡(jiǎn)化創(chuàng)建流程。進(jìn)入命令行模式后執(zhí)行下面命令來(lái)創(chuàng)建服務(wù)提供者。
php artisan make:provider EnvatoCustomServiceProvider運(yùn)行后會(huì)在 app/Providers 目錄下創(chuàng)建 EnvatoCustomServiceProvider.php 文件。打開(kāi)該文件看下它的源碼。
之前我們有提到服務(wù)提供者有兩個(gè)重要方法:boot 和 register 方法,在實(shí)現(xiàn)自定義服務(wù)提供者時(shí)大部分都是在處理這兩個(gè)方法。
register 方法用于執(zhí)行服務(wù)綁定處理。另外在 boot 方法中可以使用所有已綁定的服務(wù)。在這個(gè)教程的最后一節(jié)我們將學(xué)習(xí)更多有關(guān)這兩個(gè)方法的細(xì)節(jié),但在這里我們會(huì)先了解些這兩個(gè)方法的使用示例加深理解。
注冊(cè)自定義服務(wù)提供者前面我們創(chuàng)建了一個(gè)自定義的服務(wù)提供者。接下來(lái)需要讓 Laravel 知道如何讓這個(gè)服務(wù)提供者同其它服務(wù)提供者一樣在應(yīng)用啟動(dòng)時(shí)被加載到 Laravel 中。
為了完成注冊(cè)服務(wù)提供者的功能,僅需要將類名加入到 config/app.php 配置文件的 providers 節(jié)點(diǎn)。
"providers" => [ /* * Laravel Framework Service Providers... */ IlluminateAuthAuthServiceProvider::class, IlluminateBroadcastingBroadcastServiceProvider::class, IlluminateBusBusServiceProvider::class, IlluminateCacheCacheServiceProvider::class, IlluminateFoundationProvidersConsoleSupportServiceProvider::class, IlluminateCookieCookieServiceProvider::class, IlluminateDatabaseDatabaseServiceProvider::class, IlluminateEncryptionEncryptionServiceProvider::class, IlluminateFilesystemFilesystemServiceProvider::class, IlluminateFoundationProvidersFoundationServiceProvider::class, IlluminateHashingHashServiceProvider::class, IlluminateMailMailServiceProvider::class, IlluminateNotificationsNotificationServiceProvider::class, IlluminatePaginationPaginationServiceProvider::class, IlluminatePipelinePipelineServiceProvider::class, IlluminateQueueQueueServiceProvider::class, IlluminateRedisRedisServiceProvider::class, IlluminateAuthPasswordsPasswordResetServiceProvider::class, IlluminateSessionSessionServiceProvider::class, IlluminateTranslationTranslationServiceProvider::class, IlluminateValidationValidationServiceProvider::class, IlluminateViewViewServiceProvider::class, /* * Package Service Providers... */ LaravelTinkerTinkerServiceProvider::class, /* * Application Service Providers... */ AppProvidersAppServiceProvider::class, AppProvidersAuthServiceProvider::class, // AppProvidersBroadcastServiceProvider::class, AppProvidersEventServiceProvider::class, AppProvidersRouteServiceProvider::class, AppProvidersEnvatoCustomServiceProvider::class, ],就是如此簡(jiǎn)單,現(xiàn)在你已經(jīng)將自定義服務(wù)提供者注冊(cè)到了 Laravel 中。只不過(guò)現(xiàn)在這個(gè)服務(wù)提供者還幾乎什么都沒(méi)有處理。下一節(jié),我們將以實(shí)例演示如何使用 register 和 boot 方法。
深入講解 register 和 boot 方法起先,我們來(lái)深入研究 register 方法加深你對(duì)這個(gè)方法的理解。打開(kāi)之前創(chuàng)建的 app/Providers/EnvatoCustomServiceProvider.php 文件,加入如下代碼。
app->bind("AppLibraryServicesDemoOne", function ($app) { return new DemoOne(); }); } }這里我們做了兩個(gè)處理:
引入需要使用的 AppLibraryServicesDemoOne 服務(wù)。DemoOne 類現(xiàn)在還沒(méi)有創(chuàng)建,但之后會(huì)創(chuàng)建這個(gè)類。
在 register 方法中,我們使用服務(wù)容器的 bind 方法將服務(wù)綁定到容器。這樣,當(dāng)需要使用 AppLibraryServicesDemoOne 服務(wù)而被解析時(shí),就回調(diào)用閉包方法,創(chuàng)建實(shí)例并返回 AppLibraryServicesDemoOne 對(duì)象。
現(xiàn)在創(chuàng)建 app/Library/Services/DemoOne.php 文件。
然后,在控制器的構(gòu)造函數(shù)中注入依賴。
doSomethingUseful(); } }以上便是一個(gè)使用綁定的簡(jiǎn)單方法。事實(shí)上,對(duì)于這個(gè)示例其實(shí)并不需要?jiǎng)?chuàng)建一個(gè)服務(wù)提供者,并實(shí)現(xiàn) register 方法,因?yàn)?Laravel 還可以通過(guò) PHP 的方式功能自動(dòng)解析。
Laravel 文檔中對(duì)此有一個(gè)說(shuō)明:
如果我們的依賴無(wú)需任何接口,則無(wú)需將類綁定到容器。容器此時(shí)不需要了解創(chuàng)建對(duì)象的具體細(xì)節(jié),而可以通過(guò)反射功能實(shí)現(xiàn)自動(dòng)注入。換句話說(shuō),如果我們需要綁定的服務(wù)依賴于其它接口,創(chuàng)建服務(wù)提供者則很有必要。接著來(lái)看一個(gè)實(shí)例以加深理解。
首先,創(chuàng)建一個(gè)簡(jiǎn)單的接口 app/Library/Services/Contracts/CustomServiceInterface.php。
然后,創(chuàng)建兩個(gè)基于此接口的具體實(shí)現(xiàn)?;蛘哒f(shuō),創(chuàng)建兩個(gè)繼承此接口的實(shí)現(xiàn)類。
一個(gè)是定義在 app/Library/Services/DemoOne.php 文件中的 DemoOne 類。
類似的,還有 app/Library/Services/DemoTwo.php。
現(xiàn)在,將綁定具體類名修改為綁定接口。打開(kāi) EnvatoCustomServiceProvider.php 文件并改成如何代碼。
app->bind("AppLibraryServicesContractsCustomServiceInterface", function ($app) { return new DemoOne(); }); } }這里,我們將 DemoOne 實(shí)現(xiàn)類綁定到 AppLibraryServicesContractsCustomServiceInterface 接口。后續(xù),所有依賴 AppLibraryServicesContractsCustomServiceInterface 接口的功能都被解析成 AppLibraryServicesDemoOne 對(duì)象。 這個(gè)示例是不是更有實(shí)際意義呢?
當(dāng)然,我們還需要調(diào)整下控制器中的代碼。
doSomethingUseful(); } }或許你已經(jīng)猜到 $customServiceInstance 對(duì)象是 AppLibraryServicesDemoOne 類的實(shí)例!這種方案的優(yōu)勢(shì)在于可以很容易的替換掉 DemoOne 這個(gè)實(shí)現(xiàn)。
假如你想使用 DemoTwo 替換掉 DemoOne 服務(wù)。此時(shí),僅需簡(jiǎn)單的調(diào)整下服務(wù)提供者中的代碼 EnvatoCustomServiceProvider.php。
將:
use AppLibraryServicesDemoOne;替換成:
use AppLibraryServicesDemoTwo;然后替換:
return new DemoOne();到:
return new DemoTwo();使用同樣的手法甚至可以將自定義的實(shí)現(xiàn)替換掉任何核心服務(wù)中的依賴。不僅如此,除了 bind 方法;Laravel 服務(wù)容器還提供多種綁定方法??梢圆榭?Laravel 服務(wù)容器 文檔了解更多。
下一個(gè)主題是可以擴(kuò)展 Laravel 核心服務(wù)的 boot 方法。在這個(gè)方法中,你可以獲取所有通過(guò)服務(wù)提供者注冊(cè)到容器中的服務(wù)。通常,你會(huì)在這個(gè)方法中注冊(cè)某些功能完成后需要觸發(fā)其它操作的事件監(jiān)聽(tīng)器。
依照慣例看幾個(gè)示例先。
創(chuàng)建一個(gè)用于 Laravel 校驗(yàn)的自定義表單驗(yàn)證器。
public function boot() { Validator::extend("my_custom_validator", function ($attribute, $value, $parameters, $validator) { // validation logic goes here... }); }也許你想創(chuàng)建一個(gè) view composer。在 boot 方法中創(chuàng)建是個(gè)不錯(cuò)的選擇。
public function boot() { View::composer( "demo", "AppHttpViewComposersDemoComposer" ); }當(dāng)然在這里需要率先導(dǎo)入 IlluminateSupportFacadesView。
有時(shí),我們還需要?jiǎng)?chuàng)建一些共享數(shù)據(jù)。
public function boot() { View::share("key", "value"); }甚至可以顯示的創(chuàng)建模型綁定。
public function boot() { parent::boot(); Route::model("user", AppUser::class); }這些示例演示了 boot 方法的一些用法。只有更深入的理解,才能掌握它的使用方法!
與此同時(shí),我們需要說(shuō)再見(jiàn)了。我希望你喜歡本文所討論的主題。
結(jié)論本文討論的是服務(wù)提供者,這是本文的中心思想,盡管我們是以服務(wù)容器作為開(kāi)篇,因?yàn)樗抢斫夥?wù)提供者的重要組成部分。
隨后,我們創(chuàng)建了一個(gè)自定義服務(wù)提供者,并且在本文的后半部分中,我們介紹了幾個(gè)實(shí)際的示例。
原文: How to Register & Use Laravel Service Providers
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/28753.html
摘要:簡(jiǎn)述的生命周期采用了單一入口模式,應(yīng)用的所有請(qǐng)求入口都是文件。分發(fā)請(qǐng)求一旦應(yīng)用完成引導(dǎo)和所有服務(wù)提供者都注冊(cè)完成,將會(huì)移交給路由進(jìn)行分發(fā)。此外,由于對(duì)動(dòng)態(tài)方法的獨(dú)特用法,也使測(cè)試起來(lái)非常容易。 本書(shū)的 GitHub 地址:https://github.com/todayqq/PH... Laravel 作為現(xiàn)在最流行的 PHP 框架,其中的知識(shí)較多,所以單獨(dú)拿出來(lái)寫(xiě)一篇。 簡(jiǎn)述 La...
摘要:通過(guò)添加此功能,該程序包將啟用記錄請(qǐng)求和響應(yīng)信息所需的功能。是一條普通控制器路由,用于輸出控制臺(tái)的視圖。收集瀏覽器行為這是整個(gè)擴(kuò)展包最乏味的部分。 Laravel Dusk 控制臺(tái)是一款 Laravel 擴(kuò)展包,能夠?yàn)槟愕?Dusk 測(cè)試套件提供漂亮的可視面板。通過(guò)它,你可以可視化運(yùn)行 Dusk 測(cè)試時(shí)涉及的各個(gè)步驟,以及查看每個(gè)步驟的 DOM 快照。這對(duì)于調(diào)試瀏覽器測(cè)試、并搞清楚后臺(tái)...
showImg(https://segmentfault.com/img/bV6aHV?w=1280&h=800); 社區(qū)優(yōu)秀文章 Laravel 5.5+passport 放棄 dingo 開(kāi)發(fā) API 實(shí)戰(zhàn),讓 API 開(kāi)發(fā)更省心 - 自造車輪。 API 文檔神器 Swagger 介紹及在 PHP 項(xiàng)目中使用 - API 文檔撰寫(xiě)方案 推薦 Laravel API 項(xiàng)目必須使用的 8 個(gè)...
摘要:現(xiàn)在面向所有人正式發(fā)布了。并且有計(jì)劃將作為可選擴(kuò)展包發(fā)布,你仍然可以在項(xiàng)目中使用它們。是最新的穩(wěn)定版本,將在年月左右處理收到的錯(cuò)誤修復(fù)和更新,并在年月左右之前進(jìn)行安全修復(fù)。中文翻譯中文翻譯已啟動(dòng),請(qǐng)關(guān)注更多翻譯文章請(qǐng)見(jiàn)開(kāi)發(fā)者社區(qū) showImg(https://segmentfault.com/img/remote/1460000018318895?w=1680&h=859); Lar...
摘要:我是沒(méi)有目錄,在項(xiàng)目根目錄下運(yùn)行即可報(bào)錯(cuò)這個(gè)是應(yīng)用程序級(jí)錯(cuò)誤,先開(kāi)模式它在中,自己搜,改為即可然后就可以看到具體錯(cuò)誤,我這邊是么有初始密碼,這個(gè)通過(guò)命令行可以解決。如果你有什么問(wèn)題和疑惑關(guān)于首次安裝并運(yùn)行,歡迎留言一起探討。 本指南目標(biāo)在于指導(dǎo)萌新開(kāi)啟第一步(我也是第一步——第N次卡在第一步) 初次運(yùn)行報(bào)錯(cuò) 報(bào)錯(cuò):500 查看Apache日志后終于解決,如果報(bào)500錯(cuò)誤,就去查看服務(wù)...
閱讀 2358·2021-09-28 09:36
閱讀 2311·2021-09-22 15:14
閱讀 3714·2019-08-30 12:47
閱讀 3084·2019-08-30 12:44
閱讀 1314·2019-08-29 17:06
閱讀 602·2019-08-29 14:12
閱讀 1054·2019-08-29 14:01
閱讀 2638·2019-08-29 12:17