Laravel 6 核心概念(服務容器、服務提供者、facades、contracts、輔助函數、生命週期)

交流羣 375462817
視頻配套文檔羣文件裏面可以下載。
快速入門 https://www.bilibili.com/video/av70545323/
模型關係 https://www.bilibili.com/video/av73028135/
認證授權 https://www.bilibili.com/video/av74879198/
OAuth 2.0 https://www.bilibili.com/video/av75125939/
核心概念 https://www.bilibili.com/video/av76060293/

核心概念

簡介、服務容器、服務提供者、facade、contract、生命週期。

簡介

我叫 Laravel。我是一個裝了藥的藥箱,專門處理人們的問題、治病。

人們喜歡把我的藥箱叫做 service container 服務容器。

把我的藥箱裏面的一塊一塊的小格子叫 service provider 服務提供者。在這些小格子裏可以放置不同的藥。

有的人用到我的時候,會在我的小格子或者是他們自制的格子裏面放置自己製作的藥。有些藥有副作用,比如可以治療肚子疼又能治療頭痛,這樣肚子疼、頭不疼的患者吃了可能對頭產生不良影響。所以我定了一份合同契約讓放進來的藥有個規範。並且我內置的藥也是有契約來規範約束我自己。他們把我的這個合同稱爲 contract 契約。

有些藥片很難看,可以把它用糖衣包裝起來,這樣小孩子更容易吞食使用。我裏面很多藥都用了這種包裝,藥效沒增加,但是更容易使用。人們後期添加的藥也可以自制包裝。這種包裝稱之爲 facade 門面。

一、藥箱(服務容器)

綁定,解析,解析事件(類似於在藥瓶中放藥,取藥,取藥事項)。

放藥(綁定)

基礎綁定

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

綁定單例

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

綁定實例

$api = new HelpSpot\API(new HttpClient);

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

綁定實例時給定初始化數據

$this->app->when('App\Http\Controllers\UserController')
          ->needs('$variableName')
          ->give($value);    // 利用上下文給綁定設置初始數據

舉個栗子

interface Fruit
{
    public function color();
}

class Apple implements Fruit
{
    public $color;

    public function __construct($color){
        $this->color = $color;
    }

    public function color(){
        return $this->color;
    }
}

app()->bind('Fruit', 'Apple');
app()->when('Apple')->needs('$color')->give('red');
echo app('Fruit')->color();

綁定接口到實例

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

根據上下文提供不同的綁定

$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');
          });

給綁定設置標籤

$this->app->bind('SpeedReport', function () {
    //
});

$this->app->bind('MemoryReport', function () {
    //
});

$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');

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

Service 已經被解析,extend 方法可以用來修改解析出來的實例 $service

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

拿藥(解析)

$this->app->make('HelpSpot\API');
app()->make('HelpSpot\API');
resolve('HelpSpot\API');
app('HelpSpot\API');
app()['HelpSpot\API']
app()->get('HelpSpot\API')
public function xxx(HelpSpot\API $users)
// 注入依賴
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
$api = app('HelpSpot\API', ['id' => 1]); 
$api = resolve('HelpSpot\API', ['id' => 1]); 
# laravel 實現了 PSR-11 接口,所以就可以用該接口的類型提示解析
use Psr\Container\ContainerInterface;
Route::get('/', function (ContainerInterface $container) {
    $service = $container->get('Service');
    //
});

容器事件

容器解析任何對象時調用

$this->app->resolving(function ($object, $app) {
    
});

容器解析HelpSpot\API時調用

$this->app->resolving(HelpSpot\API::class, function ($api, $app) {
    
});

二、藥箱裏的小格子(服務提供者)

製作一個服務提供者

  1. php artisan make:provider RiakServiceProvider
  2. 服務提供者主要由兩個方法:registerbootregister 只負責綁定一些東西到容器(放藥)。boot 可以使用類型提示解析等來完成任意你想做的事情,這些都歸功於容器調用所有服務提供者的register方法之後纔去調用boot方法。
  3. config/app.phpproviders數組中註冊服務提供者。

製作一個延遲服務提供者

如果只是綁定服務到服務容器,可以設置爲延遲(實現 DeferrableProvider 接口),在項目真正需要用到之前不會註冊。

class RiakServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register()
    {
        $this->app->singleton(Connection::class, function ($app) {
            return new Connection(config('riak'));
        });
    }

    public function provides()
    {
        return [Connection::class];
    }
}

三、Facades

不要在一個類中,用太多的facades。過於臃腫的情況下應該將大類分解成幾個小類。

優點

方便測試(輔助函數和 facades 沒什麼區別,測試方法也是一樣的)。

Route::get('/cache', function () {
    return Cache::get('key');     // === return cache('key');
});
public function testBasicExample()
{
    Cache::shouldReceive('get')
         ->with('key')
         ->andReturn('value');

    $this->visit('/cache')
         ->see('value');
}

實時的 facades

原生用法 vs 實時用法

# 原生用法 class Podcast
use App\Contracts\Publisher;
public function publish(Publisher $publisher)
{
    $this->update(['publishing' => now()]);
    $publisher->publish($this);
}
# 實時用法
use Facades\App\Contracts\Publisher;

Publisher::publish($this);

測試實時的 facades

use Facades\App\Contracts\Publisher;
Publisher::shouldReceive('publish')->once()->with($podcast);

facades 列表

Facade Class Service Container Binding
App Illuminate\Foundation\Application app
Artisan Illuminate\Contracts\Console\Kernel artisan
Auth Illuminate\Auth\AuthManager auth
Auth (Instance) Illuminate\Contracts\Auth\Guard auth.driver
Blade Illuminate\View\Compilers\BladeCompiler blade.compiler
Broadcast Illuminate\Contracts\Broadcasting\Factory  
Broadcast (Instance) Illuminate\Contracts\Broadcasting\Broadcaster  
Bus Illuminate\Contracts\Bus\Dispatcher  
Cache Illuminate\Cache\CacheManager cache
Cache (Instance) Illuminate\Cache\Repository cache.store
Config Illuminate\Config\Repository config
Cookie Illuminate\Cookie\CookieJar cookie
Crypt Illuminate\Encryption\Encrypter encrypter
DB Illuminate\Database\DatabaseManager db
DB (Instance) Illuminate\Database\Connection db.connection
Event Illuminate\Events\Dispatcher events
File Illuminate\Filesystem\Filesystem files
Gate Illuminate\Contracts\Auth\Access\Gate  
Hash Illuminate\Contracts\Hashing\Hasher hash
Lang Illuminate\Translation\Translator translator
Log Illuminate\Log\LogManager log
Mail Illuminate\Mail\Mailer mailer
Notification Illuminate\Notifications\ChannelManager  
Password Illuminate\Auth\Passwords\PasswordBrokerManager auth.password
Password (Instance) Illuminate\Auth\Passwords\PasswordBroker auth.password.broker
Queue Illuminate\Queue\QueueManager queue
Queue (Instance) Illuminate\Contracts\Queue\Queue queue.connection
Queue (Base Class) Illuminate\Queue\Queue  
Redirect Illuminate\Routing\Redirector redirect
Redis Illuminate\Redis\RedisManager redis
Redis (Instance) Illuminate\Redis\Connections\Connection redis.connection
Request Illuminate\Http\Request request
Response Illuminate\Contracts\Routing\ResponseFactory  
Response (Instance) Illuminate\Http\Response  
Route Illuminate\Routing\Router router
Schema Illuminate\Database\Schema\Builder  
Session Illuminate\Session\SessionManager session
Session (Instance) Illuminate\Session\Store session.store
Storage Illuminate\Filesystem\FilesystemManager filesystem
Storage (Instance) Illuminate\Contracts\Filesystem\Filesystem filesystem.disk
URL Illuminate\Routing\UrlGenerator url
Validator Illuminate\Validation\Factory validator
Validator (Instance) Illuminate\Validation\Validator  
View Illuminate\View\Factory view
View (Instance) Illuminate\View\View

四、Contracts

FacadesContracts 沒有什麼值得注意的區別,但是當你開發第三方包的時候,最好使用 Contracts,這樣有利於你編寫測試,否則如果使用 Facades,因爲是第三方包,將不能訪問 facade 測試函數。

使用方法

在構造函數中類型提示注入就行了。

Contracts 列表

Contract References Facade
Illuminate\Contracts\Auth\Access\Authorizable  
Illuminate\Contracts\Auth\Access\Gate Gate
Illuminate\Contracts\Auth\Authenticatable  
Illuminate\Contracts\Auth\CanResetPassword  
Illuminate\Contracts\Auth\Factory Auth
Illuminate\Contracts\Auth\Guard Auth::guard()
Illuminate\Contracts\Auth\PasswordBroker Password::broker()
Illuminate\Contracts\Auth\PasswordBrokerFactory Password
Illuminate\Contracts\Auth\StatefulGuard  
Illuminate\Contracts\Auth\SupportsBasicAuth  
Illuminate\Contracts\Auth\UserProvider  
Illuminate\Contracts\Bus\Dispatcher Bus
Illuminate\Contracts\Bus\QueueingDispatcher Bus::dispatchToQueue()
Illuminate\Contracts\Broadcasting\Factory Broadcast
Illuminate\Contracts\Broadcasting\Broadcaster Broadcast::connection()
Illuminate\Contracts\Broadcasting\ShouldBroadcast  
Illuminate\Contracts\Broadcasting\ShouldBroadcastNow  
Illuminate\Contracts\Cache\Factory Cache
Illuminate\Contracts\Cache\Lock  
Illuminate\Contracts\Cache\LockProvider  
Illuminate\Contracts\Cache\Repository Cache::driver()
Illuminate\Contracts\Cache\Store  
Illuminate\Contracts\Config\Repository Config
Illuminate\Contracts\Console\Application  
Illuminate\Contracts\Console\Kernel Artisan
Illuminate\Contracts\Container\Container App
Illuminate\Contracts\Cookie\Factory Cookie
Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
Illuminate\Contracts\Database\ModelIdentifier  
Illuminate\Contracts\Debug\ExceptionHandler  
Illuminate\Contracts\Encryption\Encrypter Crypt
Illuminate\Contracts\Events\Dispatcher Event
Illuminate\Contracts\Filesystem\Cloud Storage::cloud()
Illuminate\Contracts\Filesystem\Factory Storage
Illuminate\Contracts\Filesystem\Filesystem Storage::disk()
Illuminate\Contracts\Foundation\Application App
Illuminate\Contracts\Hashing\Hasher Hash
Illuminate\Contracts\Http\Kernel  
Illuminate\Contracts\Mail\MailQueue Mail::queue()
Illuminate\Contracts\Mail\Mailable  
Illuminate\Contracts\Mail\Mailer Mail
Illuminate\Contracts\Notifications\Dispatcher Notification
Illuminate\Contracts\Notifications\Factory Notification
Illuminate\Contracts\Pagination\LengthAwarePaginator  
Illuminate\Contracts\Pagination\Paginator  
Illuminate\Contracts\Pipeline\Hub  
Illuminate\Contracts\Pipeline\Pipeline  
Illuminate\Contracts\Queue\EntityResolver  
Illuminate\Contracts\Queue\Factory Queue
Illuminate\Contracts\Queue\Job  
Illuminate\Contracts\Queue\Monitor Queue
Illuminate\Contracts\Queue\Queue Queue::connection()
Illuminate\Contracts\Queue\QueueableCollection  
Illuminate\Contracts\Queue\QueueableEntity  
Illuminate\Contracts\Queue\ShouldQueue  
Illuminate\Contracts\Redis\Factory Redis
Illuminate\Contracts\Routing\BindingRegistrar Route
Illuminate\Contracts\Routing\Registrar Route
Illuminate\Contracts\Routing\ResponseFactory Response
Illuminate\Contracts\Routing\UrlGenerator URL
Illuminate\Contracts\Routing\UrlRoutable  
Illuminate\Contracts\Session\Session Session::driver()
Illuminate\Contracts\Support\Arrayable  
Illuminate\Contracts\Support\Htmlable  
Illuminate\Contracts\Support\Jsonable  
Illuminate\Contracts\Support\MessageBag  
Illuminate\Contracts\Support\MessageProvider  
Illuminate\Contracts\Support\Renderable  
Illuminate\Contracts\Support\Responsable  
Illuminate\Contracts\Translation\Loader  
Illuminate\Contracts\Translation\Translator Lang
Illuminate\Contracts\Validation\Factory Validator
Illuminate\Contracts\Validation\ImplicitRule  
Illuminate\Contracts\Validation\Rule  
Illuminate\Contracts\Validation\ValidatesWhenResolved  
Illuminate\Contracts\Validation\Validator Validator::make()
Illuminate\Contracts\View\Engine  
Illuminate\Contracts\View\Factory View
Illuminate\Contracts\View\View View::make()

五、請求生命週期

本節主要概括了框架運行的生命週期。

  1. 所有請求必定首先通過 public/index.php
  2. 在上述這個文件中首先加載 composer 自動加載文件,然後從 bootstrap/app.php 實例化一個服務容器。
  3. 接下來,框架會根據請求類型傳送請求至 app/Http/Kernel.php 或者 app/Console/Kernel.php
  4. app/Http/Kernel.php擴展了Illuminate\Foundation\Http\Kernel類,父類強制在處理請求前應該做哪些操作,操作內容都放到了 bootstrappers數組裏面(配置錯誤處理、配置記錄日誌、檢測應用環境、註冊和啓動服務提供者等)。子類在數組middleware中規定了請求在被處理前必須經過的一些處理(讀寫session、判斷是否處於維護模式、驗證 csrf 令牌等)。
  5. 處理請求,返回響應內容。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章