Maison  >  Article  >  cadre php  >  Explication détaillée du middleware dans le framework Laravel

Explication détaillée du middleware dans le framework Laravel

不言
不言avant
2018-10-15 14:43:103097parcourir

Cet article vous apporte une explication détaillée du middleware du framework laravel. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Le middleware Laravel est une chose très pratique, qui peut découpler une certaine logique, et dans Laravel, écrire un
middleware est également très pratique. Qui sait qui l'utilise.

1. Mode décorateur

Le middleware de Laravel utilise le mode décorateur[1], apprenons-le d'abord. Eh bien, parlons brièvement. Parlez-en ici.Ce modèle est principalement utilisé pour résoudre le problème.Lorsqu'une classe a besoin d'étendre dynamiquement des fonctions, l'utilisation de l'héritage étendra la sous-classe, et la fonction étendue est une fonction publique, ce qui n'est pas propice à la réutilisation des fonctions. et découplage de code.

Dans Laravel, la fonction qui utilise ce modèle est appelée pipeline de traitement des requêtes, c'est-à-dire 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(); //执行

Sortie :

Explication détaillée du middleware dans le framework Laravel

Il s'agit d'un pipeline simple basé sur le modèle du décorateur. Son essence est en réalité basée sur la fermeture et la récursivité.

En analysant ce programme, pour la variable $a finalement générée, sa valeur est à peu près comme MiddleStepOne.handle(MiddleStepTwo.handle(first)). , c'est donc un appel récursif. Pour le middleware de Laravel, son principe de mise en œuvre est le même.

2. Middleware et pipeline de traitement des requêtes dans Laravel

Dans Laravel, nous pouvons effectuer un prétraitement avant l'exécution de la requête en définissant le middleware .

Partez de la demande d'entrée public/index.php

Explication détaillée du middleware dans le framework Laravel

L'important est ce code : c'est-à-dire, traitement de la requête, Renvoie la réponse à la requête

$response = $kernel->handle(
$request = Illuminate\Http\Request::capture() //创建一个请求实例
);

Ensuite, nous entrons dans le noyau pour voir son implémentation spécifique dans IlluminateFoundationHttpKernel.php

Explication détaillée du middleware dans le framework Laravel

Explication détaillée du middleware dans le framework Laravel
Veuillez le lire vous-même à propos de la fonction dispatchToRouter(), je n'entrerai donc pas dans les détails ici.

La prochaine étape est la passionnante classe PipeLine

<?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 = &#39;handle&#39;;

    /**
     * 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;
    }
}

En général, l'implémentation de la classe pipeLine est similaire au décorateur que j'ai écrit auparavant. Le principal problème ici est qu'il réside à l'intérieur. la fonction

protected function carry(), pour le traitement des fermetures, des chaînes et des objets lorsque pip est une fermeture.

Je pensais que le middleware de Laravel est une chose très mystérieuse, mais après l'avoir lu, j'ai réalisé qu'il est juste comme ça, très sophistiqué. Ce modèle est également très utile dans le développement réel. Par exemple, nous sommes actuellement Un projet de passerelle a été utilisé. Puisqu'aucun framework n'a été utilisé, les conditions de jugement ont été supprimées et écrites dans le middleware, atteignant ainsi un certain degré de programmation modulaire.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer