一直在用Laravel
框架,很喜歡laravel
框架的中間件。在請求到結果以前,若是咱們想要對路由或請求進行額外的處理,簡單的加個Midleware
中間件就好了,很簡單,很方即是不是。
最近幾天看了下它的中間件的實現方式,把本身的心得感悟寫下來分享給你們。laravel
laravel
的中間件用的是管道模式,咱們先知道管道模式是什麼:設計模式
所謂管道(Pipeline)設計模式就是將會數據傳遞到一個任務序列中,管道扮演者流水線的角色,數據在這裏被處理而後傳遞到下一個步驟
管道,顧名思義,就是一個長長的流水管道,只不過加了許多閥門。因此管道模式大體須要三個角色:管道,閥門和載荷(流水)。以下圖:
閉包
UML
模型圖開始代碼以前,咱們必須先了解管道模式的模型圖
框架
根據上面的模型圖,咱們來實現本身所理解的管道模式的代碼:函數
/** * PipelineBuilder 接口 即管道 * @method pipe 存入多個閥門 * @method process 輸出 */ interface PipelineBuilderInterface { public function __construct($payload); public function pipe(StageBuilderInterface $stage); public function process(); } // 具體的管道類 class Pipeline implements PipelineBuilderInterface { protected $payload; protected $pipes = []; public function __construct($payload) { $this->payload = $payload; } public function pipe(StageBuilderInterface $stage) { $this->pipes[] = $stage; return $this; } public function process() { foreach ($this->pipes as $pipe) { call_user_func([$pipe, 'handle'], $this->payload); } } } // 閥門接口 interface StageBuilderInterface { public function handle($payload); } // 具體的閥門類 class StageOneBuilder implements StageBuilderInterface { public function handle($payload) { echo $payload .' 真是個'; } } // 具體的閥門類 class StageTwoBuilder implements StageBuilderInterface { public function handle($payload) { echo '帥氣的男人'; } } // 輸出:我真是個帥氣的男人 $pipeline = new Pipeline('我'); $pipeline->pipe(new StageOneBuilder) ->pipe(new StageTwoBuilder) ->process();
先來看看它的底層源碼:ui
return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run() ); });
上面的代碼是處理request
請求的一部分代碼,send()
獲取待處理的數據,through()
獲取中間件,then()
傳遞閉包函數。
基本上,使用laravel pipelines
你能夠將一個實例對象(object)在多個類之間傳遞,就像流水順着管道依次流淌通常,最終呢,層層傳遞,你就獲得了從頭到尾一系列執行操做的「最終」結果。this
laravel pipeline
interface PipelineInterface { public function send($traveler); public function through($stops); public function via($method); public function process(); } interface StageInterface { public function handle($payload); } class StageOne implements StageInterface { public function handle($payload) { echo $payload . ' am really an '; } } class StageTwo implements StageInterface { public function handle($payload) { echo 'awesome man'; } } class Pipe implements PipelineInterface { protected $container; protected $passable; protected $pipes = []; protected $via = 'handle'; public function __construct($container) { $this->container = $container; } public function send($passable) { $this->passable = $passable; return $this; } public function through($pipes) { $this->pipes = is_array($pipes) ? $pipes : func_get_args(); return $this; } public function via($method) { $this->via = $method; return $this; } public function process() { foreach ($this->pipes as $pipe) { call_user_func([$pipe, $this->via], $this->passable); } } } $container = 'a'; $payload = 'wa'; $pipe = new Pipe($container); // 輸出:I am really an awesome man $pipe->send($payload)->through([(new StageOne), (new StageTwo)])->process();
上面的代碼並無達到laravel
中間件的真正執行部分,例子中只是用到了管道模式的一部分。像then()
方法中還用了array_reduce
和array_reverse
函數來處理請求,這一部分有時間會進一步研究。spa