How is the middleware of Laravel implemented? This paper mainly introduces the implementation principle of Laravel middleware, and analyzes the concept, principle and related methods of laravel middleware in detail, and the use of the technique, which can be referred to by friends. We hope to help you.
Specific as follows:
#1 What is middleware?
For a Web application, before a request is actually processed, we may make a variety of judgments about the request before it can be passed on to a deeper level. And if we use if else this way, once the conditions need to be judged more and more, it makes the code more difficult to maintain, the coupling between the system will increase, and the middleware can solve the problem. We can make these judgments independent of the middleware, can be very convenient to filter requests.
Middleware in the #2 laravel
In Laravel, the implementation of middleware is actually dependent on the implementation of the class Illuminate\pipeline\pipeline, we first look at the code that triggers the middleware. It is very simple, that is, after processing the request to a closed packet can continue to pass.
Public function handle ($request, Closure $next) { //do something for $request return $next ($request);}
#3 Middleware Internal implementation
It says that middleware is implemented by pipeline, and its invocation is in Illuminate\routing\router
Return (new Pipeline ($this->container)) ->send ($request) ->through ($middleware) ->then ( function ($request) use ($route) { return $this->prepareresponse ( $request, $route->run ($request) ); });
As you can see, the middleware execution process calls three methods. Take a look at the code for these three methods:
Send method
Public function Send ($passable) { $this->passable = $passable; return $this;}
In fact, the Send method did not do anything, is to set the need to stream water in the middleware object, here is the HTTP request instance.
Through method
Public function through ($pipes) { $this->pipes = Is_array ($pipes)? $pipes: Func_get_args (); return $this;}
The through method is also simple, which is to set up what middleware needs to be processed.
Then method
Really difficult to understand, then the method code is very concise, but it is not easy to understand.
The public function and then (Closure $destination) { //then method accepts a closure as a parameter and then passes through the Getinitialslice wrapper, And Getinitialslice return is actually a closure, if you do not know what is the closure of the first to see the PHP document $firstSlice = $this->getinitialslice ($destination); Inverse middleware array, mainly using the characteristics of the stack, the use of the next $pipes = Array_reverse ($this->pipes); This call_user_func does not look at first, it is actually executed a array_reduce return of the closure of return Call_user_func ( ///And then use the array_reduce to process the array with a callback function, It is recommended to first read the PHP document to understand the array_reduce principle. In fact, arrary_reduce do not do anything, is packaging closures and then handed over to Call_user_func to perform array_reduce ($pipes, $this->getslice (), $firstSlice), $this->passable );}
Then there is no then, so it is finished all middleware, is not very elegant?
Since the second parameter of Aray_reduce requires a function, we'll focus here on the source code of the Getslice () method
protected function Getslice () { return function ($stack, $pipe) { //here $stack 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));}};}; }
See may be very dizzy, closures return closures. The simplification is Getslice () returns a function A, and function a returns function B. Why do you want to return two functions? Because we pass the object with $next ($request) in the middle of the pass, and $next ($request) means that the closure is executed, the closure is function A, and then returns function B, which can be passed on to the next middleware.
To simplify the code is:
Here $stack is actually closed packet, the first time will pass through the $firstslice this closure, each time will be passed in the following function; And $pipe is every middleware array_reduce ($pipes, function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { };}, $firstSlice);
Let's look at this section of code:
To determine whether it is a closure, here is the way to determine if the middleware form is closed, if it is executed directly and passes in the $passable[request instance] and $stack[to the next middleware, and returns the IF ($pipe instanceof Closure) { return Call_user_func ($pipe, $passable, $stack);//It's like this when it's not a closure illuminate\foundation\http\middleware\ Checkformaintenancemode Execute} else { //parse, return the name, this $parameters read a long time source or do not understand, it should be related to parameters, but does not affect our analysis list ($name, $ Parameters) = $this->parsepipestring ($pipe); Resolves the middleware instance from the container and executes the handle method return Call_user_func_array ([$this->container->make ($name), $this- Method], //$passable is the request instance, and $stack is the transitive closure array_merge ([$passable, $stack], $parameters)); }
Look at one more picture:
Each iteration passed in the last closure and need to execute the middleware, because the inverse of the array, based on the advanced post-stack features, so middleware 3 is first packaged, middleware 1 is the outermost layer. Remember, arrary_reduce he does not execute middleware code, but packaging middleware.
See here should understand, Array_reduce will eventually return to Func3, then Call_user_func (func3, $this->passable) is actually
return Call_user_func ($middleware [0]->handle, $this->passable, FUNC2);
And the handle code in our middleware is:
Public function handle ($request, Closure $next) { return $next ($request);}
This is equivalent to return Func2 ($request), where the $request is processed through the previous middleware. So the process of the finished middleware is over, it will be a bit of understanding, as long as the last is the outermost call_user_func to execute the middleware code
Related recommendations:
Laravel Optimized Split routing file
Laravel using pagination plug-ins for custom paging
Laravel writing the App interface (API)