ThinkPHP多模块架构要求按业务域划分模块并实现完全解耦:各模块自包含完整分层、通过容器服务通信、禁止全局调用、事件驱动协作、路由与中间件按模块隔离。

ThinkPHP 的多模块架构不是简单地把代码按文件夹分开,而是通过明确的职责边界和容器驱动的服务注册,让各模块真正独立运行、可替换、可测试。
模块划分要基于业务域,不是技术层
比如电商系统里,“订单”“商品”“用户”应各自为独立模块(如 app/order、app/goods、app/user),而不是按 MVC 拆成 app/model、app/controller 这种全局目录。每个模块内自包含 Controller、Service、Repository、事件监听器等,对外只暴露接口契约(如 OrderServiceInterface)。
- 模块间禁止直接 new 实例或跨模块调用 Db::name()、config() 等全局函数
- 跨模块协作必须通过容器获取服务:app()->make('order_service') 或依赖注入
- 模块入口统一由路由绑定,避免在控制器中硬编码其他模块路径
服务注册必须走服务提供者,别在公共文件里 bind()
每个模块应自带 provider.php(如 app/order/provider.php),在 register() 方法中完成服务绑定:
- 使用字符串别名绑定:$this->app->bind('order_service', \app\order\service\OrderService::class)
- 右侧必须是完整命名空间类名,不能省略 \app\order\
- 绑定前先确保类可自动加载:执行 php think optimize:autoload,再验证 class_exists('app\order\service\OrderService') 返回 true
- 绝对不要在 common.php 或 bootstrap.php 中调用 bind() —— 缺乏应用上下文,多应用模式下会失效
模块通信靠接口+事件,不直连实现
当“用户模块”需要通知“订单模块”创建成功时,不调用 OrderService::create(),而是触发事件:
立即学习“PHP免费学习笔记(深入)”;
- 用户模块内:event('user.order.created', ['user_id' => 123, 'order_no' => 'ORD2026...'])
- 订单模块在自己的 provider.php 中监听该事件,并绑定处理逻辑
- 事件参数用数组或 DTO 封装,避免传递模型实例(防止序列化失败或循环引用)
- 若需同步结果(如校验库存),定义接口 StockCheckerInterface,由用户模块通过容器获取其实现,但具体实现类(如 GoodsStockChecker)由 goods 模块提供并绑定
路由与中间件按模块隔离
模块级路由配置放在 app/{module}/route.php,而非全局 route/route.php;中间件也按模块声明:
- 在 app/order/middleware/CheckOrderPermission.php 中只处理订单相关权限
- 路由分组时指定中间件命名空间:->middleware(\app\order\middleware\CheckOrderPermission::class)
- 避免在中间件里写 if ($module === 'admin') 这类判断——这等于又耦合了模块名



















