日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Laravel-海贼王系列】第七章,Pipeline 类解析

發布時間:2025/5/22 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Laravel-海贼王系列】第七章,Pipeline 类解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Pipeline

Laravel 的中間件是通過管道類來實現的。

通過內核處理請求的過程中管道的作用來解析管道類!

protected function sendRequestThroughRouter($request){$this->app->instance('request', $request);Facade::clearResolvedInstance('request');$this->bootstrap();return (new Pipeline($this->app)) //這是個 Illuminate\Routing\Pipeline 對象,繼承了 Illuminate\Pipeline\Pipeline 對象。->send($request) // 調用 Illuminate\Pipeline\Pipeline 的 send() 方法傳入 $request 對象->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) // 傳入需要經過的中間件數組->then($this->dispatchToRouter());// 傳入最后執行的閉包并且運行管道} 復制代碼

接下來我們看看這段代碼是如何讓請求通過所有的中間件之后返回的。

代碼調用追蹤

  • 約定 (new Pipeline($this->app)) 下面統稱 $pipe

  • $pipe->send($request) // 將 $request 對象賦值給 $pipe->passable

  • $pipe->pipes 的賦值

  • array:5 [▼0 => "App\Http\Middleware\CheckForMaintenanceMode"1 => "Illuminate\Foundation\Http\Middleware\ValidatePostSize"2 => "App\Http\Middleware\TrimStrings"3 => "Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull"4 => "App\Http\Middleware\TrustProxies"]$pipe->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) 復制代碼

    4.$pipe->then($this->dispatchToRouter()); 這里是執行父類的 then() 方法

    public function then(Closure $destination){$pipeline = array_reduce(array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination));return $pipeline($this->passable);} 復制代碼

    ? array_reverse($this->pipes),就是將剛才存入的中間件順序反轉。

    ? $this->carry() 這里的 $this 指向的對象是 Illuminate\Routing\Pipeline 對象因此調用 carry() 方法是自身的。

    ? $this->prepareDestination($destination) 返回一個閉包

    return function ($passable) use ($destination) {return $destination($passable);}; 復制代碼

    接著開始看

    $pipeline = array_reduce(array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)); 復制代碼

    這段代碼可以改造成容易讀的方式

    $cb = $this->carry();$stack = $this->prepareDestination($destination);foreach (array_reverse($this->pipes) as $pipe) {$stack = $cb($stack,$pipe);}$pipeline = $stack; 復制代碼

    先獲取一個閉包,然后獲取第一個閉包參數 $stack ,之后遍歷 pipes 數組來進行迭代,每次迭代會更新下次迭代的 $stack 變量,等迭代完成之后將 $stack 賦值給 $pipeline.

    所以我們只要關心最后 $pipeline 拿到的是一個什么東西 那么這里就要解析 $this->carry() 每次執行之后返回的是什么,下面是執行調用的方法。

    protected function carry(){return function ($stack, $pipe) {return function ($passable) use ($stack, $pipe) {try {$slice = parent::carry();$callable = $slice($stack, $pipe);return $callable($passable);} catch (Exception $e) {return $this->handleException($passable, $e);} catch (Throwable $e) {return $this->handleException($passable, new FatalThrowableError($e));}};};} 復制代碼

    這里其實每次執行返回的就是個新閉包,同時 $stack,$pipe 的值也隨著調用存入閉包。為了方便我聲明下變量

    $cb = function ($passable) use ($stack, $pipe) {try {$slice = parent::carry();$callable = $slice($stack, $pipe);return $callable($passable);} catch (Exception $e) {return $this->handleException($passable, $e);} catch (Throwable $e) {return $this->handleException($passable, new FatalThrowableError($e));}}; 復制代碼

    所以上面 $cb 的值就是 $this->carry() 執行后返回的閉包就像洋蔥一樣,我們來看封裝過程。

    第一次封裝 $stack1 = $cb($passable) use ($this->prepareDestination($destination),'App\Http\Middleware\TrustProxies') 第二次封裝 $stack2 = $cb($passable) use ($stack1,'Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull') 第三次封裝 $stack3 = $cb($passable) use ($stack2,'App\Http\Middleware\TrimStrings') 第四次封裝 $stack4 = $cb($passable) use ($stack3,'Illuminate\Foundation\Http\Middleware\ValidatePostSize') 第五次封裝 $stack5 = $cb($passable) use ($stack4,'App\Http\Middleware\CheckForMaintenanceMode') 復制代碼

    最后 $pipeline 對象實際就是 $stack5。

    看到這里我們獲取了一個層層封裝的閉包,同時我們也看出為什么中間件的順序先反轉了,因為執行的時候是從 $stack5 開始的!那么下一步就是看看如何執行了。

    return $pipeline($this->passable); 復制代碼

    在遞歸完成之后我們獲得了一個 $pipeline 對象, 此時我們觸發這個閉包,后面就是連鎖反應!這里我用 $stack5 來代替 $pipeline 方便理解。 首先執行

    $stack5($this->passable,'App\Http\Middleware\CheckForMaintenanceMode') 復制代碼

    這段代碼是一個起點,也就是點燃整個連鎖反應的開始,我們來追蹤下去會回到 $cb 這個閉包的邏輯,

    $cb = function ($passable) use ($stack, $pipe) {try {$slice = parent::carry();$callable = $slice($stack, $pipe);return $callable($passable);} catch (Exception $e) {return $this->handleException($passable, $e);} catch (Throwable $e) {return $this->handleException($passable, new FatalThrowableError($e));}}; 復制代碼

    這里最終還是調用了 parent::carry(), 執行到了最里層的函數。

    protected function carry(){return function ($stack, $pipe) {return function ($passable) use ($stack, $pipe) {if (is_callable($pipe)) {return $pipe($passable, $stack);} elseif (!is_object($pipe)) {[$name, $parameters] = $this->parsePipeString($pipe);$pipe = $this->getContainer()->make($name);$parameters = array_merge([$passable, $stack], $parameters);} else {$parameters = [$passable, $stack];}$response = method_exists($pipe, $this->method)? $pipe->{$this->method}(...$parameters): $pipe(...$parameters);return $response instanceof Responsable? $response->toResponse($this->container->make(Request::class)): $response;};};} 復制代碼

    到這里我們已經進入最后的堡壘,由于傳入的 $pipe 是中間件的名稱,不是閉包所以進入 elseif 中開始執行。 第一次執行:

    $stack5 = $cb($passable) use ($stack4,'App\Http\Middleware\CheckForMaintenanceMode') 復制代碼function ($passable) use ($stack, $pipe) {if (is_callable($pipe)) {return $pipe($passable, $stack);} elseif (!is_object($pipe)) {// 進入這里開始執行[$name, $parameters] = $this->parsePipeString($pipe);$pipe = $this->getContainer()->make($name); // 從通過Application對象從容器中生產對應的類,這里不拓展了,就是應用了容器的特性來生產類。$parameters = array_merge([$passable, $stack], $parameters); // 這里非常重要,將 $passable (就是開始的 $request 對象) 和 $stack (就是最近一次調用的$stack4) 合并成數組} else {$parameters = [$passable, $stack];}$response = method_exists($pipe, $this->method)? $pipe->{$this->method}(...$parameters): $pipe(...$parameters); // 調用中間件中$pipe->handle($request, $stack4)return $response instanceof Responsable? $response->toResponse($this->container->make(Request::class)): $response;}; 復制代碼

    分析完上面并沒有完成,最后代碼運行到

    $this->method = 'handle'; 默認配置,可以通過 $this->via($method) 來修改。$response = method_exists($pipe, $this->method)? $pipe->{$this->method}(...$parameters): $pipe(...$parameters); // ...$parameters 解構數組參數實際調用 $pipe->handle($request, $stack4) 復制代碼

    此時只是調用一次閉包,那么之前封裝了那么多層都怎么辦呢?

    接下來我們分析 CheckForMaintenanceMode 中間件的 handle($request, Closure $next) 方法。

    public function handle($request, Closure $next){if ($this->app->isDownForMaintenance()) {$data = json_decode(file_get_contents($this->app->storagePath().'/framework/down'), true);if (isset($data['allowed']) && IpUtils::checkIp($request->ip(), (array) $data['allowed'])) {return $next($request);}if ($this->inExceptArray($request)) {return $next($request);}throw new MaintenanceModeException($data['time'], $data['retry'], $data['message']);}return $next($request);} 復制代碼

    return $next($request); 這句話點亮了一切

    實際調用了 $stack4($request) , 我們來看看當時 $stack4 這個閉包里面是啥

    $stack4 = $cb($passable) use ($stack3,'Illuminate\Foundation\Http\Middleware\ValidatePostSize') 復制代碼

    是不是和 $stack5 有點像, 直到這里形成了遞歸, 同時解答了為什么中間件的格式要按照文檔上面說用。

    回到最初的封裝

    第一次封裝 $stack1 = $cb($passable) use ($this->prepareDestination($destination),'App\Http\Middleware\TrustProxies') 第二次封裝 $stack2 = $cb($passable) use ($stack1,'Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull') 第三次封裝 $stack3 = $cb($passable) use ($stack2,'App\Http\Middleware\TrimStrings') 第四次封裝 $stack4 = $cb($passable) use ($stack3,'Illuminate\Foundation\Http\Middleware\ValidatePostSize') 第五次封裝 $stack5 = $cb($passable) use ($stack4,'App\Http\Middleware\CheckForMaintenanceMode') 復制代碼

    我們的調用鏈就變成了

    $stack5 = $cb($passable) use ($stack4,'App\Http\Middleware\CheckForMaintenanceMode') $stack4 = $cb($passable) use ($stack3,'Illuminate\Foundation\Http\Middleware\ValidatePostSize') $stack3 = $cb($passable) use ($stack2,'App\Http\Middleware\TrimStrings') $stack2 = $cb($passable) use ($stack1,'Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull') $stack1 = $cb($passable) use ($this->prepareDestination($destination),'App\Http\Middleware\TrustProxies') 復制代碼

    最后執行

    $this->prepareDestination($destination)$destination = $this->dispatchToRouter();return function ($passable) use ($destination) {return $destination($passable); }; // 返回一個 $response 對象 ...復制代碼

    到這里管道的核心代碼就結束了,當然是通過在內核啟動周期中 關于請求發送到路由獲取響應這個實例來解析。

    laravel 中路由對系統的管道做了細微的拓展,整體還是沒啥變化,就是閉包套閉包,不停地調用,就像剝洋蔥。

    總結

    以上是生活随笔為你收集整理的【Laravel-海贼王系列】第七章,Pipeline 类解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 日韩国产毛片 | 中文字幕1区 | 日韩一区中文 | av中文字幕观看 | 欧美69式性猛交 | 免费色av| 激情91视频| 日韩中文字幕 | 美女少妇毛片 | 麻豆av片| 日韩簧片在线观看 | 久久午夜片 | 中文字幕一区二区三区四区免费看 | 久久精品视频久久 | 香蕉视频在线观看网站 | 99黄色| 福利精品在线 | 亚洲成人中文 | 国内爆初菊对白视频 | 亚洲天堂最新 | 亚洲精品字幕在线 | 久久久久久久久久久久国产精品 | 中文在线亚洲 | 聚色av| www.亚洲天堂.com | 69精品| 能免费看18视频网站 | aa片在线观看视频在线播放 | 黄色在线免费 | 亚洲在线激情 | 性久久久久久久久久 | 久草免费在线观看视频 | 成人自拍视频网站 | 草逼视频网 | 星铁乱淫h侵犯h文 | 国产免费一区二区三区免费视频 | 乌克兰黄色片 | 美女又爽又黄又免费 | 91大奶| 超碰男人天堂 | 成人小视频免费在线观看 | 色伊伊| 欧美中文字幕视频 | 电影中文字幕 | 日韩精品视频久久 | 国产麻豆成人精品av | 久久久久国产精品区片区无码 | 日韩一区欧美二区 | 国产交换配乱淫视频免费 | 亚洲性在线 | 国产成人精品免高潮费视频 | 日韩香蕉视频 | 合欢视频污 | av超碰在线观看 | 国产专区欧美专区 | 久草视频免费看 | 国内一区二区 | 哺乳援交吃奶在线播放 | 日日噜噜夜夜狠狠久久丁香五月 | 久久老司机精品视频 | 色婷婷狠狠操 | 色偷偷av男人的天堂 | 日韩在线高清 | 一区二区精品视频 | 国产一区二区三区免费观看视频 | 男人天堂99 | 超级变态重口av番号 | 亚洲一区二区三区免费观看 | 亚洲乱码国产乱码精品 | 岛国片在线免费观看 | youjizz.com国产 | 国产xxxx18| 亚洲天堂一级 | 污网站在线看 | 亚洲小视频在线播放 | 影音先锋在线观看视频 | 91直接看| 国产又白又嫩又爽又黄 | 羞羞答答一区 | 精品人妻一区二区三区香蕉 | 大地资源高清播放在线观看 | 国产二区视频在线观看 | 久操国产在线 | 超碰人人擦 | 国语对白对话在线观看 | 波多野在线播放 | 欧美亚洲一级片 | 少妇与公做了夜伦理 | 调教亲女小嫩苞h文小说 | 午夜黄色小视频 | 国产精品久久毛片 | 欧美黄色视屏 | 中文精品久久久久人妻不卡 | 丁香啪啪 | 色哟哟视频网站 | 久久久久亚洲av成人网人人软件 | 加勒比精品 | 蜜臀av性久久久久蜜臀aⅴ麻豆 | 欧美视频观看 |