ThinkPHP 6 多应用模式不支持单入口绑定多域名,须由 Nginx/Apache 按域名转发至对应应用入口或在 public/index.php 开头通过 define('APP_PATH', ...) 或 App::bind() 动态指定应用路径,且 APP_PATH 必须最早定义、App::bind() 需在 App::run() 前调用。

ThinkPHP 多应用模式下如何通过域名区分不同项目
直接结论:ThinkPHP 6 的多应用模式本身不支持「一个入口绑多个域名」,必须靠 Web 服务器(Nginx/Apache)把不同域名的请求,分别转发到对应的应用入口文件,或统一入口后由 App::bind() 或 App::setAppPath() 动态切换应用路径。
常见错误现象是:所有域名都访问到默认应用(比如 app),或者报错 App not exists。本质是没在请求进来时明确告诉框架「这次该跑哪个应用」。
- Web 服务器层最稳:每个域名配独立
index.php入口(如www.a.com/index.php指向app/a),适合长期维护 - 统一入口 + 域名路由判断次之:在
public/index.php开头加判断逻辑,调用App::bind('a')或修改APP_PATH常量,但要注意App::bind()必须在think\Container初始化前执行 - 别在
route.php里做域名跳转——那是路由层,应用已经启动,再切应用会出错
为什么不能只改 config/app.php 中的 app_name
app_name 是运行时标识,不是启动开关。它不影响框架加载哪个应用目录,只影响日志、缓存键等辅助行为。真正决定加载哪个应用的是 APP_PATH 常量和 App::getAppPath() 返回的路径。
典型误操作:在 config/app.php 里写 'app_name' => $_SERVER['HTTP_HOST'] === 'a.com' ? 'a' : 'b' —— 这段代码根本不会被执行,因为配置文件加载早于域名获取,且 $_SERVER 可能未初始化。
立即学习“PHP免费学习笔记(深入)”;
-
APP_PATH是硬编码常量,默认指向app/,必须在public/index.php最开头就define('APP_PATH', ...) -
App::bind()要在think\App::run()之前调用,否则框架已按默认路径初始化完毕 - 如果用了 Swoole 或 RoadRunner,还要注意进程复用导致
APP_PATH被污染,每次请求都得重置
Nginx 配置域名映射到不同应用的实操要点
这是生产环境最推荐的方式:不碰 PHP 层逻辑,靠 Nginx 把请求精准打到对应应用入口。核心是让每个域名有自己的 root,并确保 index.php 能正确找到其所在应用的 app 目录。
示例配置片段(关键部分):
server {
listen 80;
server_name a.com;
root /var/www/thinkphp/public_a;
index index.php;
<pre class="brush:php;toolbar:false;">location ~ \.php$ {
fastcgi_pass php-fpm;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
# 注意这里:让 PHP 知道当前入口属于哪个应用
fastcgi_param APP_PATH /var/www/thinkphp/app_a/;
}}
server { listen 80; server_name b.com; root /var/www/thinkphp/public_b; index index.php;
location ~ \.php$ {
fastcgi_pass php-fpm;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param APP_PATH /var/www/thinkphp/app_b/;
}}
- 每个域名用独立
public_x目录,里面放一份index.php,仅修改其中的APP_PATH定义 - 不要共用同一个
public/目录然后靠if ($host == 'a.com')切换——Nginx 的if在location块里有陷阱,容易失效 -
$realpath_root比$document_root更可靠,避免符号链接问题
多项目共用内核时,runtime 和 vendor 怎么隔离
共用 vendor 没问题,Composer 自动处理;但 runtime 必须分开,否则日志、缓存、模板编译会互相覆盖。
做法很简单:在每个应用的 config/app.php 里单独配 runtime_path,指向各自目录,例如:
'runtime_path' => dirname(__DIR__) . '/runtime_a/',
- 千万别留默认的
../runtime/,那是所有应用共享的雷区 - 如果用了 Redis 缓存,记得在
config/cache.php里给每个应用设不同的prefix,不然缓存键会撞车 - 数据库迁移、命令行任务(
php think migrate)也得指定--app参数,否则默认操作主应用
最易被忽略的是命令行场景:开发时习惯在根目录跑 php think,但没加 --app=a,结果迁移表建到了错的应用里,查半天才发现。



















