最近想看看laravel的原始碼,感覺頭大,程式碼太多,層次太深,但是結構優美,語法基本代表php的標準,所以計劃花點時間好好閱讀一下,順便記下筆記,以便隨時檢視。但是我計劃先一個點一個點的弄懂,最後再做總結,可能順序不太友好,本人能力有限,若理解不到位的地方,希望大神指點,或者噴都可以,本人內心強大,希望結交更多志同道合的朋友一起學習交流進步。
laravel pipline
簡單介紹下中介軟體的作用過濾請求,長話短說,Illuminate\Foundation\Http\Kernel
裡面的方法140行左右
protected function sendRequestThroughRouter($request)
{
$this->app->instance('request', $request);
Facade::clearResolvedInstance('request');
$this->bootstrap();
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
}
看send (設定初始請求物件也就是$request
),through(就是要過濾的中介軟體類) 和 then (就是返回一個閉包函式)方法 最主要是then方法 大家可以去看看
public function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)
);
return $pipeline($this->passable);
}
laravel 的pipline 很巧妙 你可以用命令鏈模式去做pipline 但是laravel 巧妙地用到 array_reduce這個函式累積特性 加上i閉包函式的use 屬效能儲存作用域變數的特性,具體細節 我也不清楚,然後 我根據自己的理解 自己做了個例子
class a {
public static function test($request,$next){
return $next($request);
}
}
class b {
public static function test($request,$next){
return $next($request);
}
}
class c {
public static function test($request,$next){
return $next($request);
}
}
$test = [a::class];
$prepareDestination = function ($a){var_dump($a);};
$pipline = array_reduce(
array_reverse($test),
function($stack,$pip){
return function($passable) use($stack,$pip){
print_r($static);
$pip::test($passable, $stack);
};
},function($request)use($prepareDestination){$prepareDestination($request);});
$pipline([1]);
我只是想用自己簡單的例子去理解它的pipline 因為它的初次看起來很心慌,原理差不多
接下來我寫一些上面的一段程式碼發生了什麼,如果大家去自己寫一箇中介軟體的話
public function handle($request, Closure $next)
{
if (!$request->user()) {
}
return $next($request);
}
這裡的$next 其實就是閉包函式(上面的$pipline)只不過每次經過一箇中介軟體處理後 $next($request),相當於執行上一次返回的閉包,廢話少說,直接上圖 或者程式碼
先讓$test=[a::class];
然後我們 列印 $stack
例1
Closure Object
(
[static] => Array
(
[prepareDestination] => Closure Object
(
[parameter] => Array
(
[$a] => <required>
)
)
)
[parameter] => Array
(
[$request] => <required>
)
)
然後讓$test = [a::class,b::clas]
例2
Closure Object
(
[static] => Array
(
[stack] => Closure Object
(
[static] => Array
(
[prepareDestination] => Closure Object
(
[parameter] => Array
(
[$a] => <required>
)
)
)
[parameter] => Array
(
[$request] => <required>
)
)
[pip] => b
)
[parameter] => Array
(
[$passable] => <required>
)
)
Closure Object
(
[static] => Array
(
[prepareDestination] => Closure Object
(
[parameter] => Array
(
[$a] => <required>
)
)
)
[parameter] => Array
(
[$request] => <required>
)
)
然後可以在加上$test = [a::class,b::class,c::class]; 大家去列印看看
下面說明一下具體流程
當array_reduce 第一次執行時候時候 執行第二個引數閉包 注意 此時 use裡面的 $stack(是第三個引數$prepareDestination
) 和 $pip(倒轉後第一個 b::class) ,執行後返回一個閉包,上面倆引數被儲存起來了,接著執行第二次 注意此時的 use裡面的 $stack(是第一次返回的閉包) $pip
(a::class
) 然後又返回一個閉包,這個閉包裡也儲存著上面倆引數 。
其實最後得到的$pipline 就是一個閉包(第二次返回的閉包$stack儲存著第一次返回的閉包依次類推)
$pipline = function($passable) use($stack,$pip){
print_r($stack);
//var_dump($pip);
$pip::test($passable, $stack);
}
不過此時$stack是一個閉包相當於例2 不過他的$stack是上一次返回的閉包,也等於
$stack = function($passable) use($stack,$pip){
print_r($stack);
//var_dump($pip);
$pip::test($passable, $stack);
}
不過此時的 use 裡面的 $stack 引數 也是上一次返回的閉包,依次類推,直到我們預設的$prepareDestination閉包
最後當我們執行$pipline([1])
時候 裡面的[1]
實際就是我們的$request, 也就執行裡面的 $pip::test($passable, $stack);
注意此時的$pip 是 a類, $passable 是 [1] , $stack我們第一次返回的閉包例2,然後執行a 中的 return $next($request)
;· 此時 $next 就是我們第一次返回的閉包, 執行第一次返回的閉包 , 還記得第一次閉包裡面的連引數儲存的什麼嗎? 其實上面說過 $stack(第零次返回的閉包預設是第三個引數$prepareDestination
) 和 $pip(倒轉後第一個 b::class);所以一直執行下去;
最後總結一下 array_reduce 第一次生返回的閉包的倆use引數是預設的$prepareDestination和$test陣列倒轉後的第一個引數,array_reduce 第二次返回的閉包$pipline 的倆use引數是第一次返回的閉包和$test陣列倒轉後的第二個引數, 那麼執行$pipline 的時候第一次$next($request)
相當於執行第一次的返回的閉包,第一次閉包裡面也有$next($request) 相當於執行預設$prepareDestination 閉包; laravel 的原理跟這個差不多,這這是我自己的理解,理解有誤希望多多指教。
本作品採用《CC 協議》,轉載必須註明作者和本文連結