<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Laravel 底層原理:門(mén)面(Facades)

          共 2392字,需瀏覽 5分鐘

           ·

          2020-08-10 00:29

          簡(jiǎn)介

          Facades 為應(yīng)用服務(wù)容器中的綁定類(lèi)提供了一個(gè)“靜態(tài)”接口。

          Laravel 內(nèi)置了很多 Facades ,可以訪(fǎng)問(wèn)絕大部分 Laravel 的功能。

          Laravel 的門(mén)面作為服務(wù)容器中底層類(lèi)的“靜態(tài)代理”,相比于傳統(tǒng)靜態(tài)方法,在維護(hù)時(shí)能夠提供更加易于測(cè)試、更加靈活、簡(jiǎn)明優(yōu)雅的語(yǔ)法。

          Laravel 的所有門(mén)面都定義在 Illuminate\Support\Facades 命名空間下。

          我們可以輕松訪(fǎng)問(wèn)到門(mén)面:

          use?Illuminate\Support\Facades\Cache;Route::get('/cache', function () {    return Cache::get('key');});

          在整個(gè) Laravel 文檔中,很多例子使用了門(mén)面來(lái)演示框架的各種功能特性。

          何時(shí)使用 Facades

          門(mén)面有諸多優(yōu)點(diǎn),其提供了簡(jiǎn)單、易記的語(yǔ)法,讓我們無(wú)需記住長(zhǎng)長(zhǎng)的類(lèi)名即可使用 Laravel 提供的功能特性,此外,由于他們對(duì) PHP 動(dòng)態(tài)方法的獨(dú)到用法,使得它們很容易測(cè)試。

          在使用 Facades 時(shí),有些地方還需要特別注意。

          使用 Facades 最主要的風(fēng)險(xiǎn)就是會(huì)引起類(lèi)作用范圍的膨脹。

          因?yàn)?Facades 使用起來(lái)非常簡(jiǎn)單而且不需要注入,就會(huì)使得我們?cè)诓唤?jīng)意間在單個(gè)類(lèi)中使用許多 Facades,從而導(dǎo)致類(lèi)變的越來(lái)越大。

          而使用依賴(lài)注入的時(shí)候,使用的類(lèi)越多,構(gòu)造方法就會(huì)越長(zhǎng),在視覺(jué)上就會(huì)引起注意,提醒你這個(gè)類(lèi)有點(diǎn)龐大了。因此在使用 Facades 的時(shí)候,要特別注意控制好類(lèi)的大小,讓類(lèi)的作用范圍保持短小。

          在開(kāi)發(fā)與 Laravel 進(jìn)行交互的第三方擴(kuò)展包時(shí),建議最好選擇注入 Laravel 契約 ,而不是使用 Facades 的方式來(lái)使用類(lèi)。因?yàn)閿U(kuò)展包是在 Laravel 本身之外構(gòu)建,所以你無(wú)法使用 Laravel Facades 測(cè)試輔助函數(shù)。

          Facades Vs. 依賴(lài)注入

          依賴(lài)注入的主要優(yōu)點(diǎn)之一是切換注入類(lèi)的實(shí)現(xiàn)的能力。這在測(cè)試的時(shí)候很有用,因?yàn)槟憧梢宰⑷胍粋€(gè) mock 或者 stub ,并斷言在 stub 上調(diào)用的各種方法。

          通常,真正的靜態(tài)方法是不可能被 mock 或者 stub。但是,因?yàn)?Facades 使用動(dòng)態(tài)方法來(lái)代理從服務(wù)容器解析的對(duì)象的方法調(diào)用,我們可以像測(cè)試注入的類(lèi)實(shí)例一樣來(lái)測(cè)試 Facades。例如,像下面的路由:

          1. use Illuminate\Support\Facades\Cache;

          2. ?

          3. Route::get('/cache', function () {

          4. ? ? return Cache::get('key');

          5. })

          我們可以這樣編寫(xiě)測(cè)試來(lái)驗(yàn)證 Cache::get 方法以我們期望的方式被調(diào)用:

          1. use Illuminate\Support\Facades\Cache;

          2. /**

          3. * 一個(gè)基礎(chǔ)功能的測(cè)試用例。

          4. *

          5. * @return void

          6. */

          7. public function testBasicExample()

          8. {

          9. Cache::shouldReceive('get')

          10. ->with('key')

          11. ->andReturn('value');

          12. $this->visit('/cache')

          13. ->see('value');

          14. }

          Facades Vs. 輔助函數(shù)

          除了 Facades, Laravel 還包含各種「輔助函數(shù)」來(lái)實(shí)現(xiàn)一些常用的功能,比如生成視圖、觸發(fā)事件、調(diào)度任務(wù)或者發(fā)送 HTTP 響應(yīng)。

          許多輔助函數(shù)的功能都有與之對(duì)應(yīng)的 Facade。例如,下面這個(gè) Facade 的調(diào)用和輔助函數(shù)的作用是一樣的:

          1. return View::make('profile');

          2. return view('profile');

          這里的 Facades 和輔助函數(shù)之間沒(méi)有實(shí)際的區(qū)別。當(dāng)你使用輔助函數(shù)時(shí),你可以使用對(duì)應(yīng)的 Facade 進(jìn)行測(cè)試。例如,下面的路由:

          1. Route::get('/cache', function () {

          2. return cache('key');

          3. });

          在底層,輔助函數(shù) cache 實(shí)際上是調(diào)用了 Cache facade 中的 get 方法。

          因此,盡管我們使用的是輔助函數(shù),我們依然可以編寫(xiě)以下測(cè)試來(lái)驗(yàn)證該方法是否使用我們預(yù)期的參數(shù)來(lái)調(diào)用:

          1. use Illuminate\Support\Facades\Cache;

          2. /**

          3. * 一個(gè)基礎(chǔ)功能的測(cè)試用例。

          4. *

          5. * @return void

          6. */

          7. public function testBasicExample()

          8. {

          9. Cache::shouldReceive('get')

          10. ->with('key')

          11. ->andReturn('value');

          12. $this->visit('/cache')

          13. ->see('value');

          14. }

          Facades 工作原理

          在 Laravel 應(yīng)用中,門(mén)面就是一個(gè)為容器中的對(duì)象提供訪(fǎng)問(wèn)方式的類(lèi)。該機(jī)制的原理由 Facade 類(lèi)實(shí)現(xiàn)。

          不管是 Laravel 自帶的 Facades,還是用戶(hù)自定義的 Facades ,都繼承自 Illuminate\Support\Facades\Facade 類(lèi)。

          門(mén)面類(lèi)只需要實(shí)現(xiàn)一個(gè)方法:getFacadeAccessor。正是 getFacadeAccessor 方法定義了從容器中解析什么,然后 Facade 基類(lèi)使用魔術(shù)方法 __callStatic() 從你的門(mén)面中調(diào)用解析對(duì)象。

          在下面的例子中,調(diào)用了 Laravel 的緩存系統(tǒng)。通過(guò)瀏覽這段代碼,可以假定在 Cache 類(lèi)中調(diào)用了靜態(tài)方法 get:

          1. namespace App\Http\Controllers;

          2. use Illuminate\Support\Facades\Cache;

          3. use App\Http\Controllers\Controller;

          4. class UserController extends Controller

          5. {

          6. /**

          7. * 顯示給定用戶(hù)的信息。

          8. *

          9. * @param int $id

          10. * @return Response

          11. */

          12. public function showProfile($id)

          13. {

          14. $user = Cache::get('user:'.$id);

          15. return view('profile', ['user' => $user]);

          16. }

          17. }

          在上面這段代碼中,我們「導(dǎo)入」了 Cache Facade 。這個(gè) Facade 作為訪(fǎng)問(wèn) Illuminate\Contracts\Cache\Factory 接口底層實(shí)現(xiàn)的代理。我們使用 Facade 進(jìn)行的任何調(diào)用都將傳遞給 Laravel 緩存服務(wù)的底層實(shí)例。

          如果我們看一下 Illuminate\Support\Facades\Cache 這個(gè)類(lèi),你會(huì)發(fā)現(xiàn)類(lèi)中根本沒(méi)有 get 這個(gè)靜態(tài)方法:

          1. class Cache extends Facade

          2. {

          3. /**

          4. * 獲取組件的注冊(cè)名稱(chēng)。

          5. *

          6. * @return string

          7. */

          8. protected static function getFacadeAccessor() { return 'cache'; }

          9. }

          Cache Facade 繼承了 Facade 的基類(lèi),并定義了 getFacadeAccessor() 方法。這個(gè)方法的作用是返回服務(wù)容器綁定的類(lèi)的名稱(chēng)。

          當(dāng)用戶(hù)調(diào)用 Cache Facade 中的任何靜態(tài)方法時(shí), Laravel 會(huì)從 服務(wù)容器 中解析 cache 綁定,然后在解析出的對(duì)象上調(diào)用所有的請(qǐng)求方法(本例中是 get)。

          實(shí)時(shí)門(mén)面

          使用實(shí)時(shí)門(mén)面,可以將應(yīng)用中的任意類(lèi)當(dāng)做門(mén)面來(lái)使用。

          為了說(shuō)明如何使用這個(gè)功能,我們先看一個(gè)替代方案。例如我們假設(shè) Podcast 模型有一個(gè) publish 方法,盡管如此,為了發(fā)布博客,我們需要注入 Publisher 實(shí)例:

          1. namespace App;

          2. use App\Contracts\Publisher;

          3. use Illuminate\Database\Eloquent\Model;

          4. class Podcast extends Model

          5. {

          6. /**

          7. * Publish the podcast.

          8. *

          9. * @param Publisher $publisher

          10. * @return void

          11. */

          12. public function publish(Publisher $publisher)

          13. {

          14. $this->update(['publishing' => now()]);

          15. $publisher->publish($this);

          16. }

          17. }

          因?yàn)榭梢阅M注入的發(fā)布服務(wù),所以注入發(fā)布實(shí)例到該方法后允許我們輕松在隔離狀態(tài)下測(cè)試該方法。不過(guò),這要求我們每次調(diào)用 publish 方法時(shí),都要傳遞一個(gè)發(fā)布服務(wù)實(shí)例。

          使用實(shí)時(shí)門(mén)面,我們可以在維持這種易于測(cè)試的前提下不必顯式傳遞 Publisher 實(shí)例。要生成一個(gè)實(shí)時(shí)門(mén)面,在導(dǎo)入類(lèi)前面加上 Facades 命名空間前綴即可:

          1. namespace App;

          2. use Facades\App\Contracts\Publisher;

          3. use Illuminate\Database\Eloquent\Model;

          4. class Podcast extends Model

          5. {

          6. /**

          7. * Publish the podcast.

          8. *

          9. * @return void

          10. */

          11. public function publish()

          12. {

          13. $this->update(['publishing' => now()]);

          14. Publisher::publish($this);

          15. }

          16. }

          使用實(shí)時(shí)門(mén)面后,發(fā)布服務(wù)實(shí)例將會(huì)通過(guò)使用 Facades 前綴后的接口或類(lèi)名在服務(wù)容器中解析。

          在測(cè)試的時(shí)候,我們可以使用 Laravel 自帶的門(mén)面測(cè)試輔助函數(shù)來(lái)模擬這個(gè)方法調(diào)用。

          1. namespace Tests\Feature;

          2. use App\Podcast;

          3. use Tests\TestCase;

          4. use Facades\App\Contracts\Publisher;

          5. use Illuminate\Foundation\Testing\RefreshDatabase;

          6. class PodcastTest extends TestCase

          7. {

          8. use RefreshDatabase;

          9. /**

          10. * A test example.

          11. *

          12. * @return void

          13. */

          14. public function test_podcast_can_be_published()

          15. {

          16. $podcast = factory(Podcast::class)->create();

          17. Publisher::shouldReceive('publish')->once()->with($podcast);

          18. $podcast->publish();

          19. }

          20. }

          Facade 類(lèi)參考

          下面列出了每個(gè)門(mén)面及其對(duì)應(yīng)的底層類(lèi)。

          這是一個(gè)查找給定 Facade 類(lèi) API 文檔的工具。服務(wù)容器綁定的可用鍵值也包含在內(nèi)。

          Facade類(lèi)服務(wù)容器綁定
          AppIlluminate\Foundation\Applicationapp
          ArtisanIlluminate\Contracts\Console\Kernelartisan
          AuthIlluminate\Auth\AuthManagerauth
          BladeIlluminate\View\Compilers\BladeCompilerblade.compiler
          BusIlluminate\Contracts\Bus\Dispatcher
          CacheIlluminate\Cache\Repositorycache
          ConfigIlluminate\Config\Repositoryconfig
          CookieIlluminate\Cookie\CookieJarcookie
          CryptIlluminate\Encryption\Encrypterencrypter
          DBIlluminate\Database\DatabaseManagerdb
          DB (Instance)Illuminate\Database\Connection
          EventIlluminate\Events\Dispatcherevents
          FileIlluminate\Filesystem\Filesystemfiles
          GateIlluminate\Contracts\Auth\Access\Gate
          HashIlluminate\Contracts\Hashing\Hasherhash
          LangIlluminate\Translation\Translatortranslator
          LogIlluminate\Log\Writerlog
          MailIlluminate\Mail\Mailermailer
          NotificationIlluminate\Notifications\ChannelManager
          PasswordIlluminate\Auth\Passwords\PasswordBrokerManagerauth.password
          QueueIlluminate\Queue\QueueManagerqueue
          Queue (Instance)Illuminate\Contracts\Queue\Queuequeue
          Queue (Base Class)Illuminate\Queue\Queue
          RedirectIlluminate\Routing\Redirectorredirect
          RedisIlluminate\Redis\Databaseredis
          RequestIlluminate\Http\Requestrequest
          ResponseIlluminate\Contracts\Routing\ResponseFactory
          RouteIlluminate\Routing\Routerrouter
          SchemaIlluminate\Database\Schema\Blueprint
          SessionIlluminate\Session\SessionManagersession
          Session (Instance)Illuminate\Session\Store
          StorageIlluminate\Contracts\Filesystem\Factoryfilesystem
          URLIlluminate\Routing\UrlGeneratorurl
          ValidatorIlluminate\Validation\Factoryvalidator
          Validator (Instance)Illuminate\Validation\Validator
          ViewIlluminate\View\Factoryview
          View (Instance)Illuminate\View\View

          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩久久精品国产亚洲AV成人 | 婷婷五月丁香狠狠撸 | 国产中文字幕二区 | 在线观看免费无码 | 亚洲在线观看免费视频 |