本文目录导读:

- 方案一:基于领域/业务模块划分(推荐,适用于MVC框架)
- 方案二:DDD(领域驱动设计)分层(适用于大型复杂项目)
- 方案三:按功能层级划分(传统的扁平结构,适合小型项目)
- 方案四:微服务拆分(独立项目 + 共用基建)
- 实际操作中的最佳实践建议
- 快速启动模板(基于 Laravel 风格的模块化推荐)
在PHP项目中划分业务目录模块,核心原则是按业务领域(Domain)拆分,而不是按技术类型(Controller、Model、View)来写,这样能确保高内聚、低耦合,方便多人协作和后期维护。
以下是当前PHP主流项目(如基于Laravel、ThinkPHP、Symfony或自研框架)推荐的几种目录划分方案,从简单到复杂,供你参考:
基于领域/业务模块划分(推荐,适用于MVC框架)
这是目前最主流、最适合中大型项目的做法,核心思想是:一个业务模块就是一个小型完整应用。
project/ ├── app/ │ ├── Http/ │ │ ├── Controllers/ │ │ │ ├── Admin/ # 后台管理 │ │ │ │ ├── UserController.php │ │ │ │ └── OrderController.php │ │ │ └── Api/ # API接口 │ │ │ ├── V1/ # 版本控制 │ │ │ └── V2/ │ │ └── Middleware/ │ │ │ ├── Models/ # 数据库模型(可保留,但更推荐放领域) │ │ │ ├── Modules/ # 【核心】按业务模块划分 │ │ ├── User/ # 用户模块 │ │ │ ├── Controllers/ # 模块内部的控制器 │ │ │ ├── Models/ # 模块内部的模型 │ │ │ ├── Services/ # 模块业务逻辑层 │ │ │ ├── Repositories/ # 数据仓储层(可选) │ │ │ ├── Requests/ # 表单验证 │ │ │ ├── Resources/ # API资源转换 │ │ │ └── Tests/ # 单元测试 │ │ │ │ │ ├── Order/ # 订单模块 │ │ │ ├── Controllers/ │ │ │ ├── Models/ │ │ │ ├── Services/ │ │ │ └── ... │ │ │ │ │ └── Payment/ # 支付模块 │ │ └── ... │ │ │ └── Exceptions/ # 异常处理 │ ├── config/ ├── database/ │ ├── migrations/ # 数据库迁移(可按模块分文件) │ └── seeds/ ├── routes/ # 路由文件 │ ├── web.php # 前端页面路由 │ ├── api.php # API路由 │ └── admin.php # 后台路由 ├── resources/ # 视图文件 │ └── views/ │ ├── admin/ │ └── modules/ # 按模块存放视图 └── tests/
优点:
- 业务内聚性强,修改一个模块功能时,不会影响其他模块。
- 新成员入职只需要关注自己负责的模块目录。
- 未来可以很容易把某个模块拆成独立微服务。
适用场景:ERP、电商、OA、SaaS等业务逻辑复杂的系统。
DDD(领域驱动设计)分层(适用于大型复杂项目)
如果你的项目业务极度复杂(如金融、医疗、工业软件),推荐引入领域层,结构会更清晰。
project/ ├── app/ │ ├── Application/ # 应用层(调度、DTO、用例) │ │ └── UseCases/ │ │ ├── CreateOrderUseCase.php │ │ └── UserRegisterUseCase.php │ │ │ ├── Domain/ # 领域层(核心业务规则) │ │ ├── User/ │ │ │ ├── User.php # 实体 │ │ │ ├── UserRepository.php # 仓储接口 │ │ │ └── UniqueEmailSpec.php# 业务规约 │ │ └── Order/ │ │ └── ... │ │ │ ├── Infrastructure/ # 基础设施层(数据库、队列、第三方) │ │ ├── Repositories/ │ │ │ └── UserRepositoryEloquent.php │ │ └── Services/ │ │ └── PaymentGateway.php │ │ │ ├── Interfaces/ # 接口层(HTTP、CLI等) │ │ ├── Controllers/ │ │ ├── Requests/ │ │ └── Resources/ │ │ │ └── Shared/ # 公共工具、值对象 │ └── ValueObject/ │ └── Money.php │ └── routes/
优点:
- 严格遵守单一职责,业务逻辑与框架解耦。
- 适合需要长期迭代、业务模型稳定的项目。
缺点:
- 初期搭建成本高,不太适合简单项目。
按功能层级划分(传统的扁平结构,适合小型项目)
对于CRUD为主的简单项目(如博客、公司官网),可以简单按技术职责划分。
project/ ├── app/ │ ├── Controller/ │ │ ├── HomeController.php │ │ ├── PostController.php │ │ └── UserController.php │ ├── Model/ │ │ ├── Post.php │ │ └── User.php │ ├── Service/ │ │ ├── PostService.php │ │ └── UserService.php │ └── Helper/ ├── config/ ├── view/ └── route/
优点:简单直接,上手快。
缺点:随着项目复杂度增加,一个 Controller 会膨胀到几千行,难以维护。不建议用于中型以上项目。
微服务拆分(独立项目 + 共用基建)
如果项目规模很大,团队人员多,可以按业务拆分为独立的微服务项目。
project-root/
├── services/
│ ├── user-service/ # 用户微服务(独立项目)
│ │ ├── app/
│ │ ├── config/
│ │ ├── database/
│ │ └── composer.json
│ │
│ ├── order-service/ # 订单微服务
│ │ └── ...
│ │
│ └── payment-service/ # 支付微服务
│ └── ...
│
└── shared/ # 共用库(通过Composer包引入)
├── contracts/ # 接口契约
└── common/ # 公共工具类
优点:独立部署、独立开发。
缺点:分布式中的事务、通信、运维复杂度高。
实际操作中的最佳实践建议
无论你采用哪种方案,以下几个原则能让你的目录更清晰:
每个模块内尽量自闭环
不要跨模块直接调用另一个模块的Model,应通过 Service 层或 接口(Interface) 进行交互,订单模块需要用户信息,应通过 UserService::getUserInfo() 而不是 User::find()。
区分“通用模块”与“业务模块”
Modules/ ├── Common/ # 通用模块(工具类、文件上传、短信、日志) ├── Admin/ # 管理后台(权限、菜单、角色) ├── User/ # 用户模块 ├── Order/ # 订单模块 └── Payment/ # 支付模块
Common模块没有业务耦合,所有模块都可以依赖它。- 其他业务模块之间尽量不要有相互依赖,如果需要,通过 Event/Listener 或 Service 接口 解耦。
命名空间规范化
在 composer.json 中配置 PSR-4 自动加载,让命名空间与目录结构一一对应。
{
"autoload": {
"psr-4": {
"App\\Modules\\User\\": "app/Modules/User/",
"App\\Modules\\Order\\": "app/Modules/Order/"
}
}
}
这样在代码中就可以写:
use App\Modules\User\Services\UserService;
根据项目规模选择合适的方案
| 项目类型 | 推荐方案 | 示例目录结构 |
|---|---|---|
| 个人博客、展示型网站 | 方案三(功能层级) | Controller + Model + View |
| 电商(3-5人团队) | 方案一(业务模块) | Modules/User,Modules/Order |
| 金融 / 大型SaaS(6人+) | 方案二(DDD) | Domain / Application / Infrastructure |
| 多团队并行开发 | 方案四(微服务) | services/user-service |
快速启动模板(基于 Laravel 风格的模块化推荐)
如果你现在开始一个中间大小的项目,这个结构比较稳妥:
app/ ├── Modules/ │ ├── Shopping/ │ │ ├── Controllers/ │ │ ├── Services/ │ │ ├── Models/ │ │ └── Providers/ │ ├── User/ │ │ └── ... │ └── Admin/ │ └── ... ├── Providers/ ├── Support/ # 服务提供者、门面、全局助手 └── Traits/
最后提醒一个常见的错误:不要把所有的 Model 都放在同一个 Models/ 目录下,那会导致模块边界模糊,时间长了谁也分不清哪些 Model 属于哪个功能。