摘要:至此,返回本次請(qǐng)求的響應(yīng)。最內(nèi)層即路由分發(fā),解析請(qǐng)求,返回響應(yīng)的操作代碼展示,后續(xù)分析即執(zhí)行匿名函數(shù),位于下面方法中。
Laravel 中間件 代碼展示
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()); // $this->dispatchToRouter(),后期繼續(xù) } new IlluminateRoutingPipeline($this->app): public function __construct(Container $container = null) { $this->container = $container; } public function send($passable) { $this->passable = $passable; return $this; } public function through($pipes) { #################################################################################### # $this->middleware = [ # # IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode::class, # # IlluminateFoundationHttpMiddlewareValidatePostSize::class, # # AppHttpMiddlewareTrimStrings::class, # # IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class, # # ]; # #################################################################################### $this->pipes = is_array($pipes) ? $pipes : func_get_args(); return $this; } // 中間件的本質(zhì) public function then(Closure $destination) { $pipeline = array_reduce( array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination) ); // 上面操作完之后返回一個(gè)匿名函數(shù),接受一個(gè)參數(shù) return $pipeline($this->passable); } // 注意這個(gè)是子類里面會(huì)調(diào)用的父carry,區(qū)別在于子類加入了異常處理 protected function carry() { // 接受匿名函數(shù)$stack參數(shù)和$pipe參數(shù),返回匿名函數(shù),再將此匿名函數(shù)作為第一個(gè)參數(shù)$stack迭代傳入。 return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { if ($pipe instanceof Closure) { return $pipe($passable, $stack); } elseif (! is_object($pipe)) { list($name, $parameters) = $this->parsePipeString($pipe); $pipe = $this->getContainer()->make($name); $parameters = array_merge([$passable, $stack], $parameters); } else { $parameters = [$passable, $stack]; } // 中間件作用是提供了一種方便的機(jī)制來(lái)過(guò)濾進(jìn)入應(yīng)用的 HTTP 請(qǐng)求 // $this->method默認(rèn)為handle,可通過(guò)via方法進(jìn)行設(shè)置 return $pipe->{$this->method}(...$parameters); }; }; } protected function parsePipeString($pipe) { // 不帶參數(shù)的pipe(class)或帶參數(shù)(參數(shù)以,分割)的pipe(class:param1,param2,param3...) list($name, $parameters) = array_pad(explode(":", $pipe, 2), 2, []); if (is_string($parameters)) { $parameters = explode(",", $parameters); } // $parameters為[]數(shù)組或[param1,param2,param3...] return [$name, $parameters]; } protected function prepareDestination(Closure $destination) { return function ($passable) use ($destination) { return $destination($passable); }; }
前置條件
array_reduce接受三個(gè)參數(shù),第一個(gè)參數(shù)接收數(shù)組,第二個(gè)參數(shù)函數(shù)名(也可以是匿名函數(shù),函數(shù)有兩個(gè)參數(shù),分別代表$result和$item),第三個(gè)參數(shù)(可選),該參數(shù)將被當(dāng)成是數(shù)組中的第一個(gè)值來(lái)處理,或者如果數(shù)組為空的話就作為最終返回值。
匿名函數(shù)也叫閉包函數(shù)(closures),允許臨時(shí)創(chuàng)建一個(gè)沒(méi)有指定名稱的函數(shù),通過(guò) Closure 類來(lái)實(shí)現(xiàn)的。
當(dāng)對(duì)閉包函數(shù)進(jìn)行賦值時(shí),PHP 便會(huì)自動(dòng)將此種表達(dá)式轉(zhuǎn)換成內(nèi)置類 Closure 的對(duì)象對(duì)象在進(jìn)行賦值。
當(dāng)閉包函數(shù)使用到 use 使用外部數(shù)據(jù)時(shí),會(huì)在 Closure 對(duì)象生成一個(gè) static 屬性數(shù)組進(jìn)行存放。
當(dāng)閉包函數(shù)使用到參數(shù)時(shí),會(huì)在 Closure 對(duì)象生成一個(gè) parameter 屬性數(shù)組進(jìn)行存放。
public function then(Closure $destination) { $pipeline = array_reduce( array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination) ); return $pipeline($this->passable); }
生成最終匿名函數(shù)的過(guò)程:
array_reduce執(zhí)行第一次時(shí)得到如下簡(jiǎn)化的匿名函數(shù)返回,將會(huì)繼續(xù)作為第一個(gè)參數(shù)進(jìn)行迭代: object(Closure)#id (1) { ["static"]=> array(2) { ["stack"]=> object(Closure)#1 (0) { // $this->prepareDestination($destination) } ["pipe"]=> string(15) "IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull" } } 第二次: object(Closure)#id (1) { ["static"]=> array(2) { ["stack"]=> object(Closure)#id (1) { ["static"]=> array(2) { ["stack"]=> object(Closure)#1 (0) { // $this->prepareDestination($destination) } ["pipe"]=> string(15) "IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull" } } ["pipe"]=> string(15) "AppHttpMiddlewareTrimStrings" } } 第三次: object(Closure)#id (1) { ["static"]=> array(2) { ["stack"]=> object(Closure)#id (1) { ["static"]=> array(2) { ["stack"]=> object(Closure)#id (1) { ["static"]=> array(2) { ["stack"]=> object(Closure)#1 (0) { // $this->prepareDestination($destination) } ["pipe"]=> string(15) "IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull" } } ["pipe"]=> string(15) "AppHttpMiddlewareTrimStrings" } } ["pipe"]=> string(15) "IlluminateFoundationHttpMiddlewareValidatePostSize" } }
依次類推,最終得到一個(gè)匿名函數(shù)如下(接受一個(gè)參數(shù),此匿名函數(shù)內(nèi)部使用上面遞歸形式的$pipe和$stack)。
function ($passable) { if ($pipe instanceof Closure) { return $pipe($passable, $stack); } elseif (! is_object($pipe)) { list($name, $parameters) = $this->parsePipeString($pipe); $pipe = $this->getContainer()->make($name); // 實(shí)例化middleware $parameters = array_merge([$passable, $stack], $parameters); } else { $parameters = [$passable, $stack]; } return $pipe->{$this->method}(...$parameters); // 語(yǔ)法糖模式,因?yàn)閙iddleware參數(shù)可有可無(wú) };
最終匿名函數(shù)的調(diào)用過(guò)程(從最外層開(kāi)始,這就是前面為什么要array_reverse,一層一層往里撥,整體上的處理是:$pipe若是匿名函數(shù),直接調(diào)用。若是字符串,則解析成對(duì)應(yīng)的類和參數(shù),make類,再組成參數(shù)數(shù)組。最后調(diào)用$pipe->handle)
最外層($pipe=IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode): (new IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode)->handle($passable, $stack) 執(zhí)行完前置操作后,調(diào)用$stack($passable),繼續(xù)進(jìn)行下一層 下一層($pipe=IlluminateFoundationHttpMiddlewareValidatePostSize): (new IlluminateFoundationHttpMiddlewareValidatePostSize)->handle($passable, $stack) 執(zhí)行完前置操作后,調(diào)用$stack($passable),繼續(xù)進(jìn)行下一層 **以此類推,當(dāng)每層中間件的前置任務(wù)全部完成,即遞歸執(zhí)行到最里面一層(路由分發(fā),解析請(qǐng)求,返回響 應(yīng)),再由最內(nèi)層一層一層往回走,執(zhí)行每層中間件的后置任務(wù)。至此,返回本次請(qǐng)求的響應(yīng)。**
最內(nèi)層(即路由分發(fā),解析請(qǐng)求,返回響應(yīng))的操作代碼展示,后續(xù)分析:即執(zhí)行$destination($passable)匿名函數(shù),位于下面方法中。
protected function prepareDestination(Closure $destination) { return function ($passable) use ($destination) { return $destination($passable); }; } $destination: protected function dispatchToRouter() { return function ($request) { $this->app->instance("request", $request); return $this->router->dispatch($request); }; }
說(shuō)明:
所有的后置操作,都是執(zhí)行到最內(nèi)層,遞歸往回走時(shí)才會(huì)執(zhí)行逐層執(zhí)行。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/22602.html
摘要:又限于層的內(nèi)容太多,我在這篇中將整理路由中間件控制器部分內(nèi)容。前者定義頁(yè)面路由,默認(rèn)應(yīng)用中間件組后者定義無(wú)狀態(tài)路由,會(huì)應(yīng)用中間件組。命名路由可以為指定路由或者控制器方法命名,也可以為已命名的路由生成。 showImg(https://segmentfault.com/img/remote/1460000010882838); 上圖列出了 Laravel HTTP 層的相關(guān)知識(shí)大綱。由于...
摘要:而我的新輪子也并不是專門解決它的問(wèn)題的,而是順便解決而已。概述這個(gè)包,支持在所有的項(xiàng)目中使用。一旦出現(xiàn)成員,代表允許全部。列出允許跨域請(qǐng)求的方法列表,默認(rèn)是代表所有方法。信息地址嗯,新輪子,求一波。 showImg(https://segmentfault.com/img/bV5VxN?w=844&h=656); 是的,可能了解 Laravel 的都知道,在 Laravel 中簡(jiǎn)單的設(shè)...
摘要:中的中間件是中的一個(gè)重點(diǎn)本篇將從源碼的角度去講解中的中間件洞察中的中間件是如何運(yùn)行的明白為何我們使用中間件的時(shí)候要進(jìn)行那些步驟本篇文章假設(shè)讀者已經(jīng)掌握中間件的基本用法如果不了解其用法可以移步查看中間件的使用我們都知道使用中間件有三個(gè)步驟使用 Laravel中的中間件是laravel中的一個(gè)重點(diǎn),本篇將從源碼的角度去講解Lravel中的中間件,洞察Laravel中的中間件是如何運(yùn)行的,明...
摘要:直到所有中間件都執(zhí)行完畢,最后在執(zhí)行最后的即上述的方法如果上述有地方難懂的,可以參考這邊文章內(nèi)置函數(shù)在中的使用以上是在通過(guò)全局中間件時(shí)的大致流程,通過(guò)中間件和路由中間件也是一樣的,都是采用管道流操作,詳情可翻閱源碼 簡(jiǎn)介 Laravel 中間件提供了一種方便的機(jī)制來(lái)過(guò)濾進(jìn)入應(yīng)用的 HTTP 請(qǐng)求, 如ValidatePostSize用來(lái)驗(yàn)證POST請(qǐng)求體大小、ThrottleReque...
摘要:合適和夠用是最完美的追求。比如從頁(yè)面去請(qǐng)求的資源。它允許瀏覽器向跨源服務(wù)器,發(fā)出請(qǐng)求,從而克服了只能同源使用的限制。定義在中的路由都是無(wú)狀態(tài)的,并且會(huì)應(yīng)用中間件組。 關(guān)于作者 程序開(kāi)發(fā)人員,不拘泥于語(yǔ)言與技術(shù),目前主要從事PHP和前端開(kāi)發(fā),使用Laravel和VueJs,App端使用Apicloud混合式開(kāi)發(fā)。合適和夠用是最完美的追求。 個(gè)人網(wǎng)站:http://www.linganm...
摘要:合適和夠用是最完美的追求。比如從頁(yè)面去請(qǐng)求的資源。它允許瀏覽器向跨源服務(wù)器,發(fā)出請(qǐng)求,從而克服了只能同源使用的限制。定義在中的路由都是無(wú)狀態(tài)的,并且會(huì)應(yīng)用中間件組。 關(guān)于作者 程序開(kāi)發(fā)人員,不拘泥于語(yǔ)言與技術(shù),目前主要從事PHP和前端開(kāi)發(fā),使用Laravel和VueJs,App端使用Apicloud混合式開(kāi)發(fā)。合適和夠用是最完美的追求。 個(gè)人網(wǎng)站:http://www.linganm...
閱讀 4933·2021-11-25 09:43
閱讀 1186·2021-11-24 09:38
閱讀 1892·2021-09-30 09:54
閱讀 2800·2021-09-23 11:21
閱讀 2367·2021-09-10 10:51
閱讀 2368·2021-09-03 10:45
閱讀 1163·2019-08-30 15:52
閱讀 1766·2019-08-30 14:13