2017-02-13 60 views
0

下面是Laravel的ValidatePostSize一個手柄()方法:

public function handle($request, Closure $next) 
{ 
    $max = $this->getPostMaxSize(); 

    if ($max > 0 && $request->server('CONTENT_LENGTH') > $max) { 
     throw new PostTooLargeException; 
    } 

    return $next($request); 
} 

現在,這種方法是使用$下一個($請求)呼籲另一中間件。什麼我的理解是,手柄()方法得到翻譯到$下一。我想知道這是如何發生的。

+0

查看代碼? –

+0

這是堆棧中的下一個中間件關閉。 –

+0

@MagnusEriksson查看問題的描述。我知道它的方法暗示了它的封閉性。我想知道的是handle()方法如何轉換爲閉包$ next。 –

回答

2

更深請求傳遞到應用程序(允許中間件「通行證」),只需調用$下一回調與$請求。 https://laravel.com/docs/5.4/middleware#defining-middleware

當Laravel正在處理的請求它運行堆棧中的所有適用的中間件。中間件可以設置爲在路由/控制器方法之前和/或之後運行。

爲了能夠做到這一點Laravel使用Illuminate\Pipeline\Pipeline。本質上,它使用array_reduce遍歷中間件棧然後返回一個Closure來執行中間件。美容這個來自使用array_reverse允許下一個中間件執行要傳遞到前一個。


更詳細地說明一點:

Illuminate\Foundation\Http\[email protected]被稱爲它建立了sendRequestThroughRouter其中有以下的響應:

return (new Pipeline($this->app)) 
      ->send($request) 
      ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) 
      ->then($this->dispatchToRouter()); 

PipelineIlluminate\Routing\Pipeline延伸Illuminate\Pipeline\Pipeline

以上then()方法基本上是:

->then(function ($request) { 
    $this->app->instance('request', $request); 

    return $this->router->dispatch($request); 
}) 

那麼意味着我們開始了與接受最終結果一個閉合(在這一點請記住,關閉將不會被調用)。

然後,在then()方法中,發生如上所述的array_reducearray_reverse部分。


這裏是當then()方法實際發生的一個簡單的例子(假設你知道array_reduce是如何工作的):

function then(Closure $destination) 
{ 
    $pipeline = array_reduce(

     array_reverse($this->middlewares), 

     //Remember $nextClosure is going to be the closure returned 
     //from the previous iteration 

     function ($nextClosure, $middlewareClass) { 

      //This is the $next closure you see in your middleware 
      return function ($request) use ($nextClosure, $middlewareClass) { 

       //Resolve the middleware 
       $middleware = app($middlewareClass); 

       //Call the middleware 
       return $middleware->{$this->method}($request, $nextClosure); 
      }; 
     }, 

     //The finial closure that will be called that resolves the destination 

     function ($request) use ($destination) { 
      return $destination($request); 
     } 
    ); 

    return $pipeline($this->request); 
} 

說我們有3箇中間件:

[ 
    One::class, 
    Two::class, 
    Three::class, 
]; 

上面的變量$pipeline基本上是:

function ($request) { 

    return app(One::class)->handle($request, function ($request) { 

     return app(Two::class)->handle($request, function ($request) { 

      return app(Three::class)->handle($request, function ($request) { 

       return $destination($request); 

      }); 
     };); 
    };); 
}; 

希望這會有所幫助!

+0

請您詳細說明一下好嗎?我認爲所有的魔法都發生在Illuminate/Pipeline/Pipeline.php中。一個簡單的例子會很棒。 –

+0

@MayankKumar我增加了一些。 –

+0

如果我想在不使用管道的情況下實現這個,我應該如何處理? –

1

接下來是一個封閉的,匿名函數的變量。在你的代碼中,你有return $next($request);。 $ next是基於你的第二個方法參數的Closure。這意味着你的方法的返回值是匿名函數返回的值。

例如:

// this is the Closure. 
$next = function ($parameter) { 
    return $parameter . ' This message is modified by $next'; 
}; 

public function handle($message, Closure $next) 
{ 
    return $next($message); 
} 

// test the output 
$message = 'Hello World!'; 
echo handle($message, $next); // output will be 'Hello World! This message is modified by $next' 
相關問題