Understanding Middleware Loading and Multi‑Application Parsing in ThinkPHP 6

This article explains how ThinkPHP 6 loads global middleware, details the internal methods such as loadMiddleware, import, add, and buildMiddleware, and then describes the framework's multi‑application detection and parsing logic, including relevant code examples.

php Courses
php Courses
php Courses
Understanding Middleware Loading and Multi‑Application Parsing in ThinkPHP 6

The article begins by revisiting the runWithRequest() method of the Http class, showing the call to $this->initialize(); followed by the loading of global middleware via $this->loadMiddleware();.

Middleware class initialization

The loadMiddleware method checks for a middleware.php file in the application base path and, if present, imports its contents:

protected function loadMiddleware(): void {
    if (is_file($this->app->getBasePath() . 'middleware.php')) {
        $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
    }
}

The import method receives an array of middleware classes and a type (default 'global') and forwards each entry to add():

public function import(array $middlewares = [], string $type = 'global'): void {
    foreach ($middlewares as $middleware) {
        $this->add($middleware, $type);
    }
}

The add method builds the middleware definition and stores it in a queue, ensuring uniqueness:

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);
    }
}

The core work is done by buildMiddleware, which handles arrays, closures, string aliases, nested middleware, and finally returns a normalized definition:

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];
    }
    if (is_array($middleware)) {
        $this->import($middleware, $type);
        return [];
    }
    return [[$middleware, 'handle'], $param ?? null];
}

After these steps, the global middleware queue is fully populated.

Multi‑application parsing

Following middleware loading, ThinkPHP 6 checks whether the application runs in multi‑app mode. The Http constructor sets the $this->multi flag based on the presence of a controller directory:

public function __construct(App $app) {
    $this->app = $app;
    $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
}

If multi‑app is enabled, parseMultiApp() is invoked. This method resolves the application name from domain bindings, configuration maps, or the first segment of the request path, adjusts the request root and pathinfo, and finally loads the determined application:

protected function parseMultiApp(): void {
    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', []);
            $deny = $this->app->config->get('app.deny_app_list', []);
            $path = $this->app->request->pathinfo();
            $name = current(explode('/', $path));
            if (isset($map[$name])) {
                $appName = $map[$name] instanceof \Closure ? (call_user_func_array($map[$name], [$this]) ?: $name) : $map[$name];
            } 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'));
}

The method ultimately calls loadApp() to bootstrap the selected application, mirroring the initialization steps performed for the default app.

In summary, the article walks through the complete lifecycle of global middleware registration and the decision‑making process for multi‑application routing in ThinkPHP 6, providing concrete code excerpts to illustrate each step.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

middlewareFrameworkThinkPHPMultiApp
php Courses
Written by

php Courses

php中文网's platform for the latest courses and technical articles, helping PHP learners advance quickly.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.