Maison > cadre php > PensezPHP > ThinkPHP6 chargement du middleware et analyse multi-applications

ThinkPHP6 chargement du middleware et analyse multi-applications

藏色散人
Libérer: 2021-07-13 13:52:42
avant
3498 Les gens l'ont consulté

1. Chargement du middleware

Un article que j'ai écrit auparavantanalysait l'initialisation de l'application, qui est ce qu'on appelle dans la méthode run() de l'expansion de la classe HTTP. analyse de $this->initialize(), la première ligne de code de la méthode runWithRequest(). Regardons à nouveau les premières lignes de la méthode runWithRequest() :

protected function runWithRequest(Request $request)
{
    $this->initialize();

    // 加载全局中间件
    $this->loadMiddleware();
    .
    .
    .
Copier après la connexion
Une fois l'application initialisée, l'étape suivante consiste à traiter le middleware.

Initialisation de la classe middleware

Méthode loadMiddleware :

protected function loadMiddleware(): void
{
    if (is_file($this->app->getBasePath() . 'middleware.php')) {
        $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
    }
}
Copier après la connexion
est toujours une routine courante, utilisez $this->app->middleware pour instancier le middleware et obtenir son instance.

Import middleware

Après avoir obtenu l'instance de la classe Middleware via $this->app->middleware, le programme appelle ensuite la méthode d'importation et transmet le fichier lu depuis le fichier "middleware.php" dans le dossier " app". data. Le contenu original du fichier est le suivant (tous les commentaires ont été initialement commentés) :

return [
    // 全局请求缓存
    // \think\middleware\CheckRequestCache::class,
    // 多语言加载
     \think\middleware\LoadLangPack::class,
    // Session初始化
    // \think\middleware\SessionInit::class,
    // 页面Trace调试
     \think\middleware\TraceDebug::class,
];
Copier après la connexion
Afin d'étudier comment le middleware est chargé, supprimez d'abord deux commentaires, c'est-à-dire ajoutez deux middleware. Ensuite, regardez la méthode d'importation :

public function import(array $middlewares = [], string $type = 'global'): void
{
    foreach ($middlewares as $middleware) {
        $this->add($middleware, $type);
    }
}
Copier après la connexion
Cette méthode transmet un tableau de middleware et un type de middleware. La valeur par défaut est globale. La clé est la méthode add à l'intérieur. Accédez à la méthode add :

public function add($middleware, string $type = 'route'): void
{
    if (is_null($middleware)) {
        return;
    }

    $middleware = $this->buildMiddleware($middleware, $type);

    if ($middleware) {
        $this->queue[$type][] = $middleware;
        // 去除重复
        $this->queue[$type]   = array_unique($this->queue[$type], SORT_REGULAR);
    }
}
Copier après la connexion
En fait, le vrai travail est la méthode buildMiddleware, accédez directement à :

protected function buildMiddleware($middleware, string $type): array
{
    // 是否是数组
    if (is_array($middleware)) {
        // 列出中间件及其参数
        // 这里说明我们可以给中间件传入参数,且形式为 [中间件, 参数]
        list($middleware, $param) = $middleware;
    }
    // 是否是一个闭包
    // 说明中间件可以是一个闭包
    if ($middleware instanceof \Closure) {
        //返回闭包和参数
        return [$middleware, $param ?? null];
    }
    // 排除了上面几种类型,且不是字符串,抛出错误
    if (!is_string($middleware)) {
        throw new InvalidArgumentException('The middleware is invalid');
    }

    //中间件别名检查
     $alias = $this->app->config->get('middleware.alias', []);

     if (isset($alias[$middleware])) {
        $middleware = $alias[$middleware];
    }

    //如果中间件有包含中间件(说明中间件可以嵌套)
    //再走一遍「import」递归解析
    if (is_array($middleware)) {
        $this->import($middleware, $type);
        return [];
    }
    //返回解析结果
    return [[$middleware, 'handle'], $param ?? null];
}
Copier après la connexion
Voir les commentaires de code ci-dessus pour une analyse détaillée. Le résultat final renvoyé est ajouté à une file d'attente en exécutant $ this->queue[$type][] = $middleware; Le résultat final de l'analyse ressemble probablement à ceci (app/middleware.php supprime certains commentaires sur le middleware) :

ThinkPHP6 chargement du middleware et analyse multi-applications

À ce stade, le middleware global est chargé.

2. Analyse multi-applications

Après avoir chargé le middleware, l'étape suivante est l'analyse multi-applications (ThinkPHP 6 commence à prendre en charge le mode multi-applications).

if ($this->multi) {
    $this->parseMultiApp();
}
Copier après la connexion
Notez que le constructeur de la classe Http :

public function __construct(App $app)
{
    $this->app   = $app;
    //多应用解析,通过判断「app」目录下有无「controller」目录,没有就是多应用模式
    $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
}
Copier après la connexion
Vous pouvez voir que le programme détermine s'il est en mode multi-application en jugeant s'il y a un répertoire "controller" dans le répertoire "app".

Ensuite, regardez la méthode principale parseMultiApp :

protected function parseMultiApp(): void
{
    // 虽然在「Http」的构造函数自动判断过是否开启多应用
    //如果没有controller目录,$this->multi为true,就会来到本方法
    // 接着还要看配置文件是否有配置
    if ($this->app->config->get('app.auto_multi_app', false)) {
        // 自动多应用识别
        $this->bindDomain = false;
        // 获取域名绑定
        $bind = $this->app->config->get('app.domain_bind', []);
        // 如果有域名绑定
        if (!empty($bind)) {
            // 获取当前子域名
            $subDomain = $this->app->request->subDomain();
            $domain    = $this->app->request->host(true);

            //完整域名绑定
            if (isset($bind[$domain])) {
                $appName          = $bind[$domain];
                $this->bindDomain = true;
                //子域名绑定
            } elseif (isset($bind[$subDomain])) {
                $appName          = $bind[$subDomain];
                $this->bindDomain = true;
                //二级泛域名绑定
            } elseif (isset($bind['*'])) {
                $appName          = $bind['*'];
                $this->bindDomain = true;
            }
        }
        //如果没有域名绑定
        if (!$this->bindDomain) {
            //获取别名映射
            $map  = $this->app->config->get('app.app_map', []);
            //获取禁止URL访问目录
            $deny = $this->app->config->get('app.deny_app_list', []);
            //获取当前请求URL的pathinfo信息(含URL后缀)
            // 比如 index/index/index
            $path = $this->app->request->pathinfo();
            // 比如,从index/index/index获取得index
            $name = current(explode('/', $path));
            //解析别名映射
            if (isset($map[$name])) {
                //如果这个别名映射到的是一个闭包
                //这样不知有啥用
                if ($map[$name] instanceof Closure) {
                    $result  = call_user_func_array($map[$name], [$this]);
                    $appName = $result ?: $name;
                    //直接取得应用名
                } else {
                    $appName = $map[$name];
                }
                //$name不为空且$name在$map数组中作为KEY,或者$name是禁止URL方位的目录
            } elseif ($name && (false !== array_search($name, $map) || in_array($name, $deny))) {
                throw new HttpException(404, 'app not exists:' . $name);
            } elseif ($name && isset($map['*'])) {
                $appName = $map['*'];
            } else {
                $appName = $name;
            }

            if ($name) {
                $this->app->request->setRoot('/' . $name);
                $this->app->request->setPathinfo(strpos($path, '/') ? ltrim(strstr($path, '/'), '/') : '');
            }
        }
    } else {
        $appName = $this->name ?: $this->getScriptName();
    }

    $this->loadApp($appName ?: $this->app->config->get('app.default_app', 'index'));
}
Copier après la connexion
Vous pouvez voir que la première section des informations "pathinfo" sera analysée dans le nom de l'application, comme index dans index/index/index/. En fin de méthode, la méthode loadApp est également appelée. L'opération effectuée est similaire à l'initialisation de l'application précédente, sauf que les fichiers chargés sont tous dans le répertoire de l'application.

Par rapport à la version précédente, ThinkPHP 6 semble avoir transformé le module d'origine en multi-application, car dans le cas de multi-application, le nom de l'application et le nom du module précédent sont analysés à partir de la première section de pathinfo, et le nouveau document, je n’ai pas non plus vu le contenu du module.

Recommandations associées :

Les 10 derniers didacticiels vidéo thinkphp

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!

Étiquettes associées:
source:segmentfault.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal