您好,欢迎访问一九零五行业门户网

laravel框架的中间件middleware的详解

本篇文章给大家带来的内容是关于laravel框架的中间件middleware的详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
laravel中间件是个非常方便的东西,能将一些逻辑实现解耦,并且在laravel中,
中间件的编写也是非常的方便。谁用谁知道。
1.装饰器模式
laravel中的中间件使用的就是装饰器模式,什么是[装饰器模式][1],先去了解一下吧,这里大概说一下,就是这个模式主要的就是用于解决 当一个类需要动态扩展功能的时候,使用继承的方式会让子类膨胀,并且这个扩展的功能是个公用功能的情况下,不利于功能的复用以及代码的解耦。
在laravel,使用对于使用这种模式的功能,称为请求处理管道,也就是pipeline
//公共接口interface middleware {        public static function handle(closure $next);    }//装饰器1class middlestepone implements middleware{        public static function handle(closure $next) {            echo 前期处理的第一步.<br>;            $next();            echo 后期处理的第一步.<br>;        }    }//装饰器2class 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(); //执行
输出:
这个就是一个简单的基于装饰器模式的管道。他的本质其实就是基于闭包和递归。
通过分析这个程序,对于最终生成的$a变量,它的值大概是这样的 middlestepone.handle(middlesteptwo.handle(first)),当执行的时候因为在handle中有个next()函数的存在,所以这是一个递归的调用。对于laravel的中间件,他的实现原理也是和这个一样的。
2.laravel中的中间件和请求处理管道
在laravel中,我们我们可以通过设置中间件来在请求执行之前做一些预先的处理。
从请求入口 public/index.php开始
重要的是这段代码:即 处理请求,返回请求的响应
$response = $kernel->handle($request = illuminate\http\request::capture() //创建一个请求实例);
接着我们进入kernel中看他的具体实现 illuminatefoundationhttpkernel.php中
关于dispatchtorouter()函数请大家自己去看,这里就不多说了。
接下来就是激动人心的pipeline类了,
<?phpnamespace 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;    }}
总的来说pipeline类的实现和我之前写的修饰器是差不多,这里主要麻烦的地方就在于就在于
protected function carry()函数内部,对于当pip是闭包,字符串,还有对象的处理。
之前觉得laravel的中间件是个很神秘的东西,但是看了之后才觉得也就那样,很精巧,在实际开发中这种模式也是很有帮助的,例如我们目前用的一个gateway项目,因为没有使用任何框架,所以将判断条件剥离,写入到中间件中, 这样实现了一定程度上的模块化编程。
以上就是laravel框架的中间件middleware的详解的详细内容。
其它类似信息

推荐信息