本文實例講述了Laravel的中間件實作原理。分享給大家參考,具體如下:
#1 什麼是中間件?
對於一個Web應(yīng)用程式來說,在一個請求真正處理前,我們可能會對請求做各種各樣的判斷,然後才可以讓它繼續(xù)傳遞到更深層次中。而如果我們用if else這樣子來,一旦需要判斷的條件越來越來,會使得程式碼更難以維護,系統(tǒng)間的耦合會增加,而中間件就可以解決這個問題。我們可以把這些判斷獨立出來做成中間件,可以很方便的過濾請求。
#2 Laravel中的中間件
在Laravel中,中間件的實作其實是依賴IlluminatePipelinePipeline這個類別實現(xiàn)的,我們先來看看觸發(fā)中間件的程式碼。很簡單,就是處理完後把請求轉(zhuǎn)交給閉包就可以繼續(xù)傳遞了。
public function handle($request, Closure $next) { //do something for $request return $next($request); }
? ?
#3 中間件??內(nèi)部實現(xiàn)
上面說道,中間件是靠Pipeline來實現(xiàn)的,它的調(diào)用在IlluminateRoutingRo三個方法。再來看看這三個方法的程式碼:
send方法
return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run($request) ); });
? ?
其實send方法沒做什麼事情,就是設(shè)定了需要在中間件中流水處理的對象,在這裡就是HTTP請求實例。
through方法
public function send($passable){ $this->passable = $passable; return $this; }
? ?
through方法也很簡單,就是設(shè)定一下需要經(jīng)過哪些中間件處理。
then方法
真正難懂的來了,then方法程式碼很簡潔,但是要理解可不容易。
public function through($pipes){ $this->pipes = is_array($pipes) ? $pipes : func_get_args(); return $this; }
? ?
然後就沒有然後了,這樣就過完了所有中間件,是不是很優(yōu)雅?
由於aray_reduce的第二個參數(shù)需要一個函數(shù),我們這裡重點看看getSlice()方法的源碼
public function then(Closure $destination){ //then方法接受一個閉包作為參數(shù),然后經(jīng)過getInitialSlice包裝,而getInitialSlice返回的其實也是一個閉包,如果還不知道什么是閉包先去看PHP文檔 $firstSlice = $this->getInitialSlice($destination); //反轉(zhuǎn)中間件數(shù)組,主要是利用了棧的特性,用處接下來再說 $pipes = array_reverse($this->pipes); //這個call_user_func先不要看,它其實就是執(zhí)行了一個array_reduce返回的閉包 return call_user_func( //接下來用array_reduce來用回調(diào)函數(shù)處理數(shù)組,建議先去PHP文檔讀懂a(chǎn)rray_reduce的執(zhí)行原理。其實arrary_reduce什么事情都沒干,就是包裝閉包然后移交給call_user_func來執(zhí)行 array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable ); }
? ?
看到可能會很頭暈,但閉包返回閉包的。簡化一下就是getSlice()回傳一個函數(shù)A,而函數(shù)A又回傳了函數(shù)B。為什麼要回傳兩個函數(shù)呢?因為我們中間在傳遞過程中是用$next($request)來傳遞物件的,而$nex??t($request)這樣的寫法就表示是執(zhí)行了這個閉包,這個閉包就是函數(shù)A,然後回傳函數(shù)B ,可以給下一個中間件繼續(xù)傳遞。
再來簡化程式碼就是:
protected function getSlice(){ return function ($stack, $pipe) { //這里$stack return function ($passable) use ($stack, $pipe) { if ($pipe instanceof Closure) { return call_user_func($pipe, $passable, $stack); } else { list($name, $parameters) = $this->parsePipeString($pipe); return call_user_func_array([$this->container->make($name), $this->method], array_merge([$passable, $stack], $parameters)); } }; }; }
? ?
再來看這段程式碼:
//這里的$stack其實就是閉包,第一次遍歷的時候會傳入$firstSlice這個閉包,以后每次都會傳入下面的那個function; 而$pipe就是每一個中間件 array_reduce($pipes, function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { }; }, $firstSlice);
? ?
給每一次需要執(zhí)行的中間件,由於反轉(zhuǎn)了數(shù)組,基於棧先進後出的特性,所以中間件3第一個被包裝,中間件1就在最外層了。要記得,arrary_reduce他不執(zhí)行中間件程式碼,而是包裝中間件。
看到這裡應(yīng)該明白了,array_reduce最後會回傳func3,那麼call_user_func(func3,$this->passable)實際上就是
//判斷是否為閉包,這里就是判斷中間件形式是不是閉包,是的話直接執(zhí)行并且傳入$passable[請求實例]和$stack[傳遞給下一個中間件的閉包],并且返回 if ($pipe instanceof Closure) { return call_user_func($pipe, $passable, $stack); //不是閉包的時候就是形如這樣Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode執(zhí)行 } else { //解析,把名稱返回,這個$parameters看了許久源碼還是看不懂,應(yīng)該是和參數(shù)相關(guān),不過不影響我們的分析 list($name, $parameters) = $this->parsePipeString($pipe); //從容器中解析出中間件實例并且執(zhí)行handle方法 return call_user_func_array([$this->container->make($name), $this->method], //$passable就是請求實例,而$stack就是傳遞的閉包 array_merge([$passable, $stack], $parameters)); }
而我們的中間件中的handle代碼是:
return call_user_func($middleware[0]->handle, $this->passable, func2);
就相當(dāng)於這裡就相當(dāng)於return func2($request),這裡的$request就是經(jīng)過上一個中間件處理過的。所以正果中間件的過程就完了,理解起來會有點繞,只要記得最後是由最外面的call_user_func來執(zhí)行中間件代碼的
希望本文所述對大家基於Laravel框架的PHP程式設(shè)計有所幫助。
更多Laravel中間件實現(xiàn)原理詳解相關(guān)文章請關(guān)注PHP中文網(wǎng)!

熱AI工具

Undress AI Tool
免費脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)