laravel中pipeline中间件调用

来源:互联网 发布:nginx 页面状态码修改 编辑:程序博客网 时间:2024/05/19 19:41

今天在看laravel源码代码的过程中,遇到了一个方法,就是sendRequestThroughRouter

这个方法是http核心类中的发送请求至路由


 

/**     * Send the given request through the middleware / router.     *     * @param  \Illuminate\Http\Request  $request     * @return \Illuminate\Http\Response     */    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());    }


现在主要关注点是pipeline的中间件执行代码。

创建了一个pipeline类,调用send($request),设置pipeplie当前的请求;through操作,将所有的中间件初始化到pipeline中,进行处理的是then方法。

姑且先不理$this->dispatchToRouter()这个方法的细节,这个方法主要返回 final destination callback的回调。


    /**     * Run the pipeline with a final destination callback.     *     * @param  \Closure  $destination     * @return mixed     */    public function then(Closure $destination)    {        $firstSlice = $this->getInitialSlice($destination);        $pipes = array_reverse($this->pipes);        return call_user_func(            array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable        );    }


获取最先执行的匿名函数,接着,将所有的中间件倒置。看一下array_reduce的作用,使用数组每一个元素带入回调进行执行,就是一直执行,最终返回最后一个结果。


mixed array_reduce ( array $array ,callable $callback [, mixed $initial = NULL ] )

array_reduce() applies iteratively the callback function to the elements of the array, so as to reduce the array to a single value.

array

The input array.

 

callback

mixed callback ( mixed $carry , mixed $item)

carry

Holds the return value of the previous iteration; in the case of the first iteration it instead holds the value of initial.

 

item

Holds the value of the current iteration.

 

initial

If the optional initial is available, it will be used at the beginning of the process, or as a final result in case the array is empty.

----以上摘自php manual

       通过以上说明,array_reduce就是使用传入的回调函数对数组中每个元素进行处理,最终返回操作结果。而回调的$carry参数是上一次执行返回的结果,$item则是当前数组元素。$initial参数是指第一次或者空数组时返回的结果。


    /**     * Get a Closure that represents a slice of the application onion.     *     * @return \Closure     */    protected function getSlice()    {        return function ($stack, $pipe) {            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));                }            };        };    }

getSlice得到是怎样的回调函数呢?

首先,会返回function($stack, $pipe) {},

function ($stack, $pipe) {            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));                }            };        };


接着,array_reduce第一次执行,得到function($passable)use($stack, $pipe) {}。

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,$pipe,没有被释放。

根据array_reduce的特性,array_reduce执行完后,会将返回值赋值给下一次调用的$stack。这样,这一次的结果在下一次执行中被使用。

array_reduce继续执行,直至到最后一个中间件被执行完毕。

而最后一个中间件就是倒置前的第一个中间件,最后array_reduce返回结果是function($passable) use($stack,$pipe) {}

此匿名函数会在then方法中被call_user_func执行,

call_user_func(            array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable        );


现在仅仅讨论$pipe instanceof Closure为真的情况。

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));                }


执行array_reduce最终返回的匿名函数得到返回值call_user_func($pipe,$passable, $stack);这个返回值的意思是,调用$pipe这个可执行的方法,并传入$passable,$stack参数。$stack,即上一次reduce返回的匿名函数。

 

而$pipe这个可执行的方法实际上就是中间件里面的handle方法

   

   public function handle($request, Closure $next, $guard = null)   {  //code...        return $next($request);   }

也就是说,实质就是执行$handle($passable,$stack,null),而$next($request)  == $stack($passable);

这样,上一次传入的匿名函数就会被执行。如此类推,直至所有传入的匿名函数被执行完。

 

简单来说,过程就是A接到一个任务,传给B执行。然而B不执行,说让C执行完自己的任务才执行A的,然后把自己的任务传给C。最后C执行自己的事情后再执行B给的任务,B执行A的。

以上只是个人的见解,有什么纰漏或者错误请大家指教指教微笑





0 0
原创粉丝点击