必備知識點:
閉包(Closure)、array_reduce()函式、array_reverse()函式、call_user_func()函式
裝飾者模式
資料:
《Laravel框架關鍵技術解析》
相關部落格
示例程式碼:
interface Middleware
{
public static function handle(Closure $next);
}
class VerifyCsrfToken implements Middleware
{
public static function handle(Closure $next)
{
echo "驗證 CSRF Token<br />";
$next();
}
}
class ShareErrorsFromSession implements Middleware
{
public static function handle(Closure $next)
{
echo "如果 Session中有'errors'變數, 則共享它<br />";
$next();
}
}
class StartSession implements Middleware
{
public static function handle(Closure $next)
{
echo "開啟 Session,獲取會話資料<br />";
$next();
echo "儲存會話資料,關閉 Session<br />";
}
}
class AddQueuedCookiesToResponse implements Middleware
{
public static function handle(Closure $next)
{
$next();
echo "新增下一次請求需要的cookie".'<br>';
}
}
class EncryptCookies implements Middleware
{
public static function handle(Closure $next)
{
echo "對輸入 Cookie 進行解密<br />";
$next();
echo "對輸出 Cookie 進行加密";
}
}
class CheckMaintenanceMode implements Middleware
{
public static function handle(Closure $next)
{
echo "檢測系統是否處於維護狀態<br />";
$next();
}
}
function getSlice()
{
return function ($stack, $pipe) {
return function () use ($stack, $pipe) {
return $pipe::handle($stack);
};
};
}
function then()
{
$pipes = [
CheckMaintenanceMode::class,
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
];
$firstSlice = function () {
echo "請求向路由器傳遞,返回響應<br />";
};
$pipes = array_reverse($pipes);
call_user_func(
array_reduce($pipes, getSlice(), $firstSlice)
);
}
then();
執行流程
- 剛開始執行,首先
array_reservse()
函式將$pipes
陣列倒序反轉,至於為什麼需要反轉後面再說明。 array_reduce()
將回撥函式getSlice()
迭代地作用到$pipes
陣列中的每一個單元中,而array_reduce()
設定了初始值,則第一個執行的是$firstSlice
這個函式。- 第一個執行的是
$firstSlice
這個函式,所以function ($firstSlice, VerifyCsrfToken::class) { return function ($firstSlice, VerifyCsrfToken::class) { return VerifyCsrfToken::handle($firstSlice); } }
- 執行到第二個是時候是
function (VerifyCsrfToken::class, ShareErrorsFromSession::class) { return function (VerifyCsrfToken::class, ShareErrorsFromSession::class) { return ShareErrorsFromSession::handle(function ($firstSlice, VerifyCsrfToken::class) { return function ($firstSlice, VerifyCsrfToken::class) { return VerifyCsrfToken::handle($firstSlice); } }); } }
- 以此類推….
最後變成這樣:
執行到陣列的最後一次,則是function (){ return CheckMaintenanceMode::handle(function (){ return EncryptCookies::handle(function (){ return AddQueuedCookiesToResponse::handle(function (){ return StartSession::handle(function (){ return ShareErrorsFromSession::handle(function (){ return VerifyCsrfToken::handle(function (){ echo "請求向路由器傳遞,返回響應<br />"; }) }) }); }); }); }); }
CheckMaintenanceMode::class
,然後call_user_func()
執行回撥函式,先執行CheckMaintenanceMode::class
,然後執行EncryptCookies::class
,執行順序則與未反轉前的陣列順序完全相同,這也是為什麼需要使用array_reservse()
函式進行反轉的原因。執行結果
檢測系統是否處於維護狀態 對輸入 Cookie 進行解密 開啟 Session,獲取會話資料 如果 Session中有'errors'變數, 則共享它 驗證 CSRF Token 請求向路由器傳遞,返回響應 儲存會話資料,關閉 Session 新增下一次請求需要的cookie 對輸出 Cookie 進行加密
本作品採用《CC 協議》,轉載必須註明作者和本文連結