2017-02-13 68 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' 
相关问题