国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

服務(wù)容器

服務(wù)容器


服務(wù)容器

簡(jiǎn)介

Laravel 服務(wù)容器是一個(gè)用于管理類的依賴和執(zhí)行依賴注入的強(qiáng)大工具。依賴注入這個(gè)花哨名詞實(shí)質(zhì)上是指:類的依賴通過構(gòu)造函數(shù),或者某些情況下通過 "setter" 方法 "注入" 到類中。

來看一個(gè)簡(jiǎn)單的例子:

<?php
  namespace App\Http\Controllers;
  use App\User;
  use App\Repositories\UserRepository;
  use App\Http\Controllers\Controller;
  class UserController extends Controller{   
   /**
     * 用戶存儲(chǔ)庫(kù)的實(shí)現(xiàn).
     *
     * @var UserRepository
     */  
       protected $users; 
    /**
     * 創(chuàng)建新的控制器實(shí)例.
     *
     * @param  UserRepository  $users
     * @return void
     */ 
       public function __construct(UserRepository $users) 
        {    
            $this->users = $users;  
         }  
    /**
     * 顯示指定用戶的 profile.
     *
     * @param  int  $id
     * @return Response
     */  
       public function show($id)  
         {   
            $user = $this->users->find($id);     
            return view('user.profile', ['user' => $user]);   
         }
       }

在這個(gè)例子中,控制器 UserController 需要從數(shù)據(jù)源獲取 users。因此,我們要 注入一個(gè)能夠獲取 users 的服務(wù)。在當(dāng)前上下文中,我們的 UserRepository 很可能是使用 Eloquent 從數(shù)據(jù)庫(kù)中獲取 user 信息。 然而,由于 repository 是被注入的,所以我們可以輕易地將其切換為另一個(gè)的實(shí)現(xiàn)。這種注入方式的便利之處還體現(xiàn)在當(dāng)我們?yōu)閼?yīng)用編寫測(cè)試時(shí),我們還可以輕松地 "模擬" 或創(chuàng)建 UserRepository 的虛擬實(shí)現(xiàn)。

想要構(gòu)建強(qiáng)大的大型應(yīng)用,至關(guān)重要的一件事是:要深刻地理解 Laravel 服務(wù)容器。當(dāng)然,為 Laravel 的核心代碼做出貢獻(xiàn)也一樣。

服務(wù)綁定

基礎(chǔ)綁定

由于大多數(shù)用戶的服務(wù)容器都被注冊(cè)在 服務(wù)提供者中,所以下面的大多數(shù)的例子都是在演示服務(wù)提供者中使用容器。

{tip} 如果某個(gè)容器不依賴于任何接口就沒必要去綁定類在這個(gè)容器里。容器不需要指定如何構(gòu)建這些對(duì)象,因?yàn)樗梢允褂梅瓷鋪碜詣?dòng)解析這些對(duì)象。

簡(jiǎn)單綁定

在服務(wù)提供器中,你總是可以通過 $this->app 屬性訪問容器。我們可以通過容器的 bind 方法注冊(cè)綁定,bind 方法的第一個(gè)參數(shù)為要綁定的類 / 接口名,第二個(gè)參數(shù)是一個(gè)返回類實(shí)例的 Closure

$this->app->bind('HelpSpot\API', function ($app) {
    return new HelpSpot\API($app->make('HttpClient'));
    });

注意,我們接受容器本身作為解析器的參數(shù)。然后,我們可以使用容器來解析正在構(gòu)建的對(duì)象的子依賴。

綁定一個(gè)單例

singleton 方法將類或接口綁定到只解析一次的容器中。一旦單例綁定被解析,相同的對(duì)象實(shí)例會(huì)在隨后的調(diào)用中返回到容器中:

$this->app->singleton('HelpSpot\API', function ($app) { 
   return new HelpSpot\API($app->make('HttpClient'));
   });

綁定實(shí)例

你也可以使用 instance 方法將現(xiàn)有對(duì)象實(shí)例綁定到容器中。給定的實(shí)例會(huì)始終在隨后的調(diào)用中返回到容器中:

$api = new HelpSpot\API(new HttpClient);
$this->app->instance('HelpSpot\API', $api);

綁定基本值

當(dāng)你有一個(gè)類不僅需要接受一個(gè)注入類,還需要注入一個(gè)基本值(比如整數(shù))。你可以使用上下文綁定來輕松注入你的類需要的任何值:

$this->app->when('App\Http\Controllers\UserController')
     ->needs('$variableName')          
     ->give($value);

綁定接口到實(shí)現(xiàn)

服務(wù)容器有一個(gè)很強(qiáng)大的功能,就是支持綁定接口到給定的實(shí)現(xiàn)。例如,如果我們有個(gè) EventPusher 接口 和一個(gè) RedisEventPusher 實(shí)現(xiàn)。一旦我們寫完了 EventPusher 接口的 RedisEventPusher 實(shí)現(xiàn),我們就可以在服務(wù)容器中注冊(cè)它,像這樣:

$this->app->bind(   
     'App\Contracts\EventPusher',    
     'App\Services\RedisEventPusher'
 );

這么做相當(dāng)于告訴容器:當(dāng)一個(gè)類需要實(shí)現(xiàn) EventPusher 時(shí),應(yīng)該注入 RedisEventPusher?,F(xiàn)在我們就可以在構(gòu)造函數(shù)或者任何其他通過服務(wù)容器注入依賴項(xiàng)的地方使用類型提示注入 EventPusher 接口:

use App\Contracts\EventPusher;
/**
 * Create a new class instance.
 *
 * @param  EventPusher  $pusher
 * @return void
 */
 public function __construct(EventPusher $pusher){  
   $this->pusher = $pusher;
  }

上下文綁定

有時(shí)你可能有兩個(gè)類使用了相同的接口,但你希望各自注入不同的實(shí)現(xiàn)。例如, 有兩個(gè)控制器可能依賴了 Illuminate\Contracts\Filesystem\Filesystem 契約. Laravel 提供了一個(gè)簡(jiǎn)單的,優(yōu)雅的接口來定義這個(gè)行為:

use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\PhotoController;
use App\Http\Controllers\VideoController;
use Illuminate\Contracts\Filesystem\Filesystem;
$this->app->when(PhotoController::class)   
       ->needs(Filesystem::class)          
       ->give(function () {         
            return Storage::disk('local');      
       });
$this->app->when([VideoController::class, UploadController::class])
          ->needs(Filesystem::class)          
          ->give(function () {            
             return Storage::disk('s3');   
         });

標(biāo)記

有時(shí)候,你可能需要解析某個(gè) “分類” 下的所有綁定。 比如, 你可能正在構(gòu)建一個(gè)報(bào)表的聚合器,它接收一個(gè)包含不同 Report 接口實(shí)現(xiàn)的數(shù)組。注冊(cè) Report 實(shí)現(xiàn)之后,你可以使用 tag 方法給他們分配一個(gè)標(biāo)簽:

$this->app->bind('SpeedReport', function () {
    //
});
$this->app->bind('MemoryReport', function () {  
  //
});
$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');

一旦服務(wù)被標(biāo)記,你就可以通過 tagged 方法輕松地解析它們:

$this->app->bind('ReportAggregator', function ($app) { 
   return new ReportAggregator($app->tagged('reports'));
   });

擴(kuò)展綁定

extend 方法可以修改已解析的服務(wù)。比如,當(dāng)一個(gè)服務(wù)被解析后,你可以添加額外的代碼來修飾或者配置它。 extend 方法接受一個(gè)閉包,該閉包唯一的參數(shù)就是這個(gè)服務(wù), 并返回修改過的服務(wù):

$this->app->extend(Service::class, function ($service) { 
   return new DecoratedService($service);
 });

解析實(shí)例

make 方法

你可以使用 make 方法從容器中解析出類實(shí)例。 make 方法接收你想要解析的類或接口的名字:

$api = $this->app->make('HelpSpot\API');

如果你的代碼處于無法訪問 $app 變量的位置,則可用全局輔助函數(shù) resolve 來解析:

$api = resolve('HelpSpot\API');

如果類依賴不能通過容器解析,你可以通過將它們作為關(guān)聯(lián)數(shù)組作為 makeWith 方法的參數(shù)注入:

$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);

自動(dòng)注入

另外,并且更重要的是,你可以簡(jiǎn)單地使用  "類型提示" 的方式在類的構(gòu)造函數(shù)中注入那些需要容器解析的依賴項(xiàng),包括 控制器,事件監(jiān)聽器, 隊(duì)列任務(wù),中間件,等 。實(shí)際上,這才是大多數(shù)對(duì)象應(yīng)該被容器解析的方式。

例如,你可以在控制器的構(gòu)造函數(shù)中添加一個(gè) repository 的類型提示,然后這個(gè) repository 將會(huì)被自動(dòng)解析并注入類中:

<?php
    namespace App\Http\Controllers;
    use App\Users\Repository as UserRepository;
    class UserController extends Controller{  
      /**
     * The user repository instance.
     */   
      protected $users;  
    /**
     * Create a new controller instance.
     *
     * @param  UserRepository  $users
     * @return void
     */ 
       public function __construct(UserRepository $users) 
          {      
            $this->users = $users; 
           } 
   /**
     * Show the user with the given ID.
     *
     * @param  int  $id
     * @return Response
     */  
       public function show($id) 
          {  
                //  
           }
      }

容器事件

服務(wù)容器每次解析對(duì)象會(huì)觸發(fā)一個(gè)事件,你可以使用  resolving  方法監(jiān)聽這個(gè)事件 :

$this->app->resolving(function ($object, $app) { 
   // Called when container resolves object of any type...
   });
$this->app->resolving(HelpSpot\API::class, function ($api, $app) {  
  // Called when container resolves objects of type "HelpSpot\API"...
  });

正如你所看到的,被解析的對(duì)象將會(huì)被傳入回調(diào)函數(shù),這使得你能夠在對(duì)象被傳給調(diào)用者之前給它設(shè)置額外的屬性。

PSR-11

Laravel 的服務(wù)容器實(shí)現(xiàn)了  PSR-11  接口。因此,你可以使用 PSR-11 容器 『接口類型提示』 來獲取 Laravel 容器的實(shí)例:

use Psr\Container\ContainerInterface;
Route::get('/', function (ContainerInterface $container) {   
 $service = $container->get('Service'); 
    //
  });

如果無法解析給定的標(biāo)識(shí)符,則將會(huì)引發(fā)異常。未綁定標(biāo)識(shí)符時(shí),會(huì)拋出 Psr\Container\NotFoundExceptionInterface 異常。如果標(biāo)識(shí)符已綁定但無法解析,會(huì)拋出 Psr\Container\ContainerExceptionInterface 異常。

本文章首發(fā)在 LearnKu.com 網(wǎng)站上。