Home > Article > PHP Framework > Detailed explanation of middleware in laravel framework
This article brings you a detailed explanation of the middleware of the laravel framework. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
Laravel middleware is a very convenient thing, which can decouple some logic implementations, and in laravel,
The writing of middleware is also very convenient. Who is who knows.
1. Decorator mode
The middleware in laravel uses the decorator mode. What is [decorator mode][1], let’s learn about it first Well, let’s briefly talk about it here. This model is mainly used to solve the problem. When a class needs to dynamically extend functions, using inheritance will expand the subclass, and the extended function is a public function, which is not conducive to the problem. Function reuse and code decoupling.
In laravel, the function that uses this mode is called the request processing pipeline, which is pipeline
//公共接口 interface middleware { public static function handle(Closure $next); } //装饰器1 class MiddleStepOne implements middleware{ public static function handle(Closure $next) { echo "前期处理的第一步"."<br>"; $next(); echo "后期处理的第一步"."<br>"; } } //装饰器2 class MiddleStepTwo implements middleware{ public static function handle(Closure $next) { echo "前期处理的第二步"."<br>"; $next(); echo "后期处理的第二步"."<br>"; } } function goFunc() { return function ($step,$className) { return function () use ($step,$className) { return $className::handle($step); }; }; } $pip = array( MiddleStepOne::class, MiddleStepTwo::class, ); $pip = array_reverse($pip); //反转数组,以求达到要求的顺序运行 $first = function (){ echo "前期处理完毕"."<br>"; }; //实际要处理的函数 $a = array_reduce($pip,goFunc(),$first); //遍历pip数组,并将first作为第一个参数传递进去 $a(); //执行
Output:
This is a simple pipeline based on the decorator pattern. Its essence is actually based on closure and recursion.
By analyzing this program, for the finally generated $a variable, its value is probably like MiddleStepOne.handle(MiddleStepTwo.handle(first)). When executed, because there is next( in the handle ) function exists, so this is a recursive call. For laravel's middleware, its implementation principle is the same as this.
2. Middleware and request processing pipeline in laravel
In laravel, we can do some pre-processing before request execution by setting middleware .
Start from the request entrance public/index.php
$response = $kernel->handle( $request = Illuminate\Http\Request::capture() //创建一个请求实例 );Then we enter the kernel to see its specific implementation in IlluminateFoundationHttpKernel.php
Please read it yourself about the dispatchToRouter() function, so I won’t go into details here.
<?php namespace Illuminate\Pipeline; use Closure; use RuntimeException; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Pipeline\Pipeline as PipelineContract; class Pipeline implements PipelineContract { /** * The container implementation. * * @var \Illuminate\Contracts\Container\Container */ protected $container; /** * The object being passed through the pipeline. * * @var mixed */ protected $passable; /** * The array of class pipes. * * @var array */ protected $pipes = []; /** * The method to call on each pipe. * * @var string */ protected $method = 'handle'; /** * Create a new class instance. * * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ public function __construct(Container $container = null) { $this->container = $container; } /** * Set the object being sent through the pipeline. * * @param mixed $passable * @return $this */ public function send($passable) { $this->passable = $passable; return $this; } /** * Set the array of pipes. * * @param array|mixed $pipes * @return $this */ public function through($pipes) { $this->pipes = is_array($pipes) ? $pipes : func_get_args(); return $this; } /** * Set the method to call on the pipes. * * @param string $method * @return $this */ public function via($method) { $this->method = $method; return $this; } /** * Run the pipeline with a final destination callback. * * @param \Closure $destination * @return mixed */ public function then(Closure $destination) { $pipeline = array_reduce( array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination) ); return $pipeline($this->passable); } /** * Get the final piece of the Closure onion. * * @param \Closure $destination * @return \Closure */ protected function prepareDestination(Closure $destination) { return function ($passable) use ($destination) { return $destination($passable); }; } /** * Get a Closure that represents a slice of the application onion. * * @return \Closure */ protected function carry() { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { if (is_callable($pipe)) { // If the pipe is an instance of a Closure, we will just call it directly but // otherwise we'll resolve the pipes out of the container and call it with // the appropriate method and arguments, returning the results back out. //如果pip也就中间件函数是一个闭包可调用函数,就直接返回这个闭包函数就行了 //这里我还没有找到对应的使用场景,后续补充 return $pipe($passable, $stack); } elseif (! is_object($pipe)) { list($name, $parameters) = $this->parsePipeString($pipe); // If the pipe is a string we will parse the string and resolve the class out // of the dependency injection container. We can then build a callable and // execute the pipe function giving in the parameters that are required. $pipe = $this->getContainer()->make($name); $parameters = array_merge([$passable, $stack], $parameters); } else { // If the pipe is already an object we'll just make a callable and pass it to // the pipe as-is. There is no need to do any extra parsing and formatting // since the object we're given was already a fully instantiated object. $parameters = [$passable, $stack]; } return method_exists($pipe, $this->method) ? $pipe->{$this->method}(...$parameters) : $pipe(...$parameters); }; }; } /** * Parse full pipe string to get name and parameters. * * @param string $pipe * @return array */ protected function parsePipeString($pipe) { list($name, $parameters) = array_pad(explode(':', $pipe, 2), 2, []); if (is_string($parameters)) { $parameters = explode(',', $parameters); } return [$name, $parameters]; } /** * Get the container instance. * * @return \Illuminate\Contracts\Container\Container * @throws \RuntimeException */ protected function getContainer() { if (! $this->container) { throw new RuntimeException('A container instance has not been passed to the Pipeline.'); } return $this->container; } }In general, the implementation of the pipeLine class is similar to the decorator I wrote before. The main trouble here is that protected function Inside the carry() function, the processing of pip is a closure, string, and object.
The above is the detailed content of Detailed explanation of middleware in laravel framework. For more information, please follow other related articles on the PHP Chinese website!