載入完中介軟體,接下來一步是多應用解析(ThinkPHP 6 開始支援多應用模式)。
if ($this->multi) {
$this->parseMultiApp();
}
注意到,Http
類的建構函式:
public function __construct(App $app)
{
$this->app = $app;
//多應用解析,通過判斷「app」目錄下有無「controller」目錄,沒有就是多應用模式
$this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
}
可以看到,程式是通過判斷「app」目錄下有無「controller」目錄來決定是否是多應用模式的。
接著看主要方法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'));
}
可以看到,「pathinfo」資訊的第一節會被解析成應用名稱,比如index/index/index/
中的index
。方法的最後還呼叫了loadApp
方法,執行的操作與前面應用的初始化類似,只是載入的檔案都在該應用的目錄。
跟之前的版本對比,ThinkPHP 6 貌似把原先的模組改造成了多應用,因為多應用情況下,應用名跟之前的模組名都是從pathinfo的第一節解析出來的,新的文件也沒見到模組的內容了。