1. Loading Middleware
Ein Artikel, den ich zuvor geschrieben habeanalysierte die Initialisierung der Anwendung, die in der run()-Methode der Http-Klassenerweiterung aufgerufen wird Analyse von $this->initialize(), der ersten Codezeile in der runWithRequest()-Methode. Schauen wir uns noch einmal die ersten paar Zeilen der runWithRequest()-Methode an:
protected function runWithRequest(Request $request) { $this->initialize(); // 加载全局中间件 $this->loadMiddleware(); . . .Nachdem die Anwendung initialisiert wurde, besteht der nächste Schritt darin, die Middleware zu verarbeiten. Initialisierung der Middleware-KlasseloadMiddleware-Methode:
protected function loadMiddleware(): void { if (is_file($this->app->getBasePath() . 'middleware.php')) { $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php'); } }ist immer noch eine gängige Routine. Verwenden Sie $this->app->middleware, um Middleware zu instanziieren und ihre Instanz abzurufen. Middleware importierenNachdem das Programm die Instanz der Middleware-Klasse über $this->app->middleware abgerufen hat, ruft es die Importmethode auf und übergibt die aus der Datei „middleware.php“ gelesene Datei im „ app“-Verzeichnis. Daten. Der ursprüngliche Inhalt der Datei lautet wie folgt (alle Kommentare wurden ursprünglich auskommentiert):
return [ // 全局请求缓存 // \think\middleware\CheckRequestCache::class, // 多语言加载 \think\middleware\LoadLangPack::class, // Session初始化 // \think\middleware\SessionInit::class, // 页面Trace调试 \think\middleware\TraceDebug::class, ];Um zu untersuchen, wie die Middleware geladen wird, entfernen Sie zunächst zwei Kommentare, dh fügen Sie zwei Middleware hinzu. Schauen Sie sich als nächstes die Importmethode an:
public function import(array $middlewares = [], string $type = 'global'): void { foreach ($middlewares as $middleware) { $this->add($middleware, $type); } }Diese Methode übergibt ein Array von Middleware und einen Middleware-Typ. Der Standardwert ist global. Der Schlüssel ist die darin enthaltene Add-Methode. Springen Sie zur Add-Methode:
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); } }Tatsächlich ist die eigentliche Arbeit die buildMiddleware-Methode. Gehen Sie direkt zu:
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]; }Eine detaillierte Analyse finden Sie in den obigen Codekommentaren. Das endgültig zurückgegebene Ergebnis wird einer Warteschlange hinzugefügt, indem $ this->queue[$type][] = $middleware; in der Add-Methode ausgeführt wird. Das endgültige Parsing-Ergebnis sieht wahrscheinlich so aus (app/middleware.php entfernt einige Middleware-Kommentare): An diesem Punkt wird die globale Middleware geladen. 2. Parsen mehrerer AnwendungenNach dem Laden der Middleware ist der nächste Schritt das Parsen mehrerer Anwendungen (ThinkPHP 6 beginnt mit der Unterstützung des Multianwendungsmodus).
if ($this->multi) { $this->parseMultiApp(); }Beachten Sie, dass der Konstruktor der HTTP-Klasse:
public function __construct(App $app) { $this->app = $app; //多应用解析,通过判断「app」目录下有无「controller」目录,没有就是多应用模式 $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true; }Sie können sehen, dass das Programm bestimmt, ob es sich im Mehranwendungsmodus befindet, indem es beurteilt, ob im Verzeichnis „app“ ein „Controller“-Verzeichnis vorhanden ist. Dann schauen Sie sich die Hauptmethode parseMultiApp an:
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')); }Sie können sehen, dass der erste Abschnitt der „Pfadinfo“-Informationen in den Anwendungsnamen geparst wird, z. B. index in index/index/index/. Am Ende der Methode wird auch die Methode „loadApp“ aufgerufen. Der durchgeführte Vorgang ähnelt der Initialisierung der vorherigen Anwendung, mit der Ausnahme, dass sich alle geladenen Dateien im Verzeichnis der Anwendung befinden. Im Vergleich zur Vorgängerversion scheint ThinkPHP 6 das ursprüngliche Modul in eine Mehrfachanwendung umgewandelt zu haben, da bei Mehrfachanwendungen der Anwendungsname und der vorherige Modulname aus dem ersten Abschnitt der Pfadinformationen analysiert werden Auch im neuen Dokument habe ich den Inhalt des Moduls noch nicht gesehen.