交流羣 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) {
});
二、藥箱裏的小格子(服務提供者)
製作一個服務提供者
php artisan make:provider RiakServiceProvider
- 服務提供者主要由兩個方法:
register
和boot
。register
只負責綁定一些東西到容器(放藥)。boot
可以使用類型提示解析等來完成任意你想做的事情,這些都歸功於容器調用所有服務提供者的register
方法之後纔去調用boot
方法。 - 在
config/app.php
的providers
數組中註冊服務提供者。
製作一個延遲服務提供者
如果只是綁定服務到服務容器,可以設置爲延遲(實現 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 列表
四、Contracts
Facades
和 Contracts
沒有什麼值得注意的區別,但是當你開發第三方包的時候,最好使用 Contracts
,這樣有利於你編寫測試,否則如果使用 Facades
,因爲是第三方包,將不能訪問 facade
測試函數。
使用方法
在構造函數中類型提示注入就行了。
Contracts 列表
五、請求生命週期
本節主要概括了框架運行的生命週期。
- 所有請求必定首先通過
public/index.php
。 - 在上述這個文件中首先加載
composer
自動加載文件,然後從bootstrap/app.php
實例化一個服務容器。 - 接下來,框架會根據請求類型傳送請求至
app/Http/Kernel.php
或者app/Console/Kernel.php
。 app/Http/Kernel.php
擴展了Illuminate\Foundation\Http\Kernel
類,父類強制在處理請求前應該做哪些操作,操作內容都放到了bootstrappers
數組裏面(配置錯誤處理、配置記錄日誌、檢測應用環境、註冊和啓動服務提供者等)。子類在數組middleware
中規定了請求在被處理前必須經過的一些處理(讀寫session
、判斷是否處於維護模式、驗證 csrf 令牌等)。- 處理請求,返回響應內容。