APP_MULTI_MODULE常量必须在public/index.php最开头定义且在require autoload.php前生效,写在config/app.php或用putenv均无效;多应用模式下目录结构须为app/子目录,单应用则需扁平化;域名绑定需在App::run()前调用App::bind(),且路由、URL生成、静态资源路径、中间件注册均因模式不同而行为迥异。

APP_MULTI_MODULE常量必须在入口文件最开头定义
这个常量只在public/index.php中require框架前生效,写在config/app.php里完全无效。很多人改了配置却没效果,就是卡在这一步。
多应用模式下默认为true,单应用需显式设为false:
define('APP_MULTI_MODULE', false);
require __DIR__ . '/../vendor/autoload.php';
// 后续才是 App::run()
常见错误包括:
- 把
define()放在autoload.php之后 - 在
config/app.php里写'app_multi_module' => false,框架压根不读这个键 - 用
putenv('APP_MULTI_MODULE=false'),环境变量方式对这个常量不起作用
目录结构必须和APP_MULTI_MODULE值严格匹配
切模式不是改个开关就完事,目录结构不跟着动,路由直接 404 或跳错控制器。
立即学习“PHP免费学习笔记(深入)”;
多应用模式要求app/下是子目录结构(如app/admin、app/api),单应用则必须扁平化——所有controller、model、view都在app/一级目录下,不能有app/admin/controller这种路径。
典型误操作:
- 删了
app/controller但没建app/admin,结果框架找不到任何控制器 - 保留
app/admin目录却设APP_MULTI_MODULE = false,框架会忽略app/admin,只扫描app/controller(此时为空) - 切换后没清缓存,旧的路由映射还在,导致URL仍走老路径
域名绑定应用必须在App::run()之前调用App::bind()
想用admin.example.com访问app/admin,不能靠config/app.php里的domain_bind,TP6 已废弃该配置。
正确做法是在public/index.php开头加判断逻辑:
if ($_SERVER['HTTP_HOST'] === 'admin.example.com') {
\think\App::bind('admin');
}
require __DIR__ . '/../vendor/autoload.php';
注意三点:
-
App::bind()必须在App::run()之前,且最好在autoload.php之后、App::init()之前 - 如果用了 Swoole/RoadRunner,要确保每次请求都重置绑定,避免上一个请求污染下一个
- 绑定后,框架只加载
app/admin/route.php,不会自动合并根目录下的app/route.php,所以每个应用得有自己的路由文件
Url::build()和static()函数在不同模式下行为不一致
多应用模式下Url::build('index')生成的是/admin/index,单应用下是/index;static('css/app.css')永远拼/static/css/app.css,不感知当前应用。
这意味着:
- 模板里写
{:url('index')}在多应用下可能跳到/admin/index,但你在单应用里测试时却跳/index,容易漏掉路径问题 - 如果把后台静态资源放
public/static/admin/,用static('admin/css/app.css')才对,而不是依赖函数自动推导 - 中间件注册作用域也不同:多应用下
app/admin/middleware.php只对admin生效,单应用下这个文件根本不会被加载
最麻烦的不是报错,而是这些差异不抛异常,只让页面空白或链接错乱,调试时得盯住生成的 URL 和实际加载的路由文件路径。



















