本文目录导读:

- 核心原则
- 方案一:经典分层架构(MVC变体)— 适用于大多数Web项目
- 方案二:领域驱动设计(DDD)— 适用于复杂业务系统
- 方案三:模块化/微服务单体(Modular Monolith)
- 方案四:命令行CLI工具或包(Packagist)类库
- 推荐的命名空间映射(基于方案一)
- 几个常见坑与建议
- 总结建议
在PHP项目中,合理的类文件目录规划对于项目的可维护性、可扩展性以及团队协作至关重要,以下是基于现代PHP开发实践(尤其是遵循PSR-4自动加载规范)的几种主流规划方案。
核心原则
- 遵循PSR-4自动加载:命名空间(Namespace)与目录结构一一对应,这是Composer支持的标准,也是现代PHP框架的基石。
- 单一职责:每个类文件只做一件事。
- 按功能/业务分层:将不同职责的类放入不同的顶层目录。
经典分层架构(MVC变体)— 适用于大多数Web项目
这是最常见、最成熟的结构,适合API、CMS、企业应用等。
project-root/
├── app/
│ ├── Controllers/ # 控制器:处理HTTP请求,返回响应
│ │ ├── Admin/ # 按模块分
│ │ ├── Api/ # API控制器
│ │ └── Web/ # Web页面控制器
│ ├── Models/ # 模型:数据库表映射、业务实体
│ ├── Services/ # 服务层:核心业务逻辑(如订单计算、支付处理)
│ │ ├── OrderService.php
│ │ └── PaymentService.php
│ ├── Repositories/ # 仓储层:数据访问抽象(可选但推荐)
│ │ ├── UserRepository.php
│ │ └── ProductRepository.php
│ ├── Middleware/ # 中间件:请求过滤(Auth, Log, CORS)
│ ├── Exceptions/ # 自定义异常类
│ └── Providers/ # 服务提供者(框架相关,如Laravel)
├── config/ # 配置文件
├── database/ # 数据库迁移、种子数据
├── public/ # Web入口(index.php)
├── resources/ # 视图模板、语言文件、静态资源
├── routes/ # 路由定义
├── storage/ # 日志、缓存、文件上传
├── tests/ # 单元测试、功能测试
│ ├── Unit/
│ └── Feature/
├── vendor/ # Composer依赖
├── bootstrap/ # 框架启动文件
├── .env # 环境变量
└── composer.json
核心目录说明:
- app/Models:存放与数据库表直接对应的实体类(
User.php,Order.php)。 - app/Services:关键层,将“协调多个模型”或“复杂计算”的代码从Controller中抽离,例如
CheckoutService调用CartService,InventoryService,PaymentGateway。 - app/Repositories:隔离数据源,如果将来需要从MySQL切换到Redis或MongoDB,只需修改Repository的实现,Controller和Service无需改动。
- app/Controllers:保持“瘦控制器”,只负责参数校验、调用Service、返回结果。
领域驱动设计(DDD)— 适用于复杂业务系统
当业务逻辑非常复杂(如ERP、金融系统、电商核心)时,按业务领域而非技术功能划分。
project-root/
├── src/
│ ├── Context/ # 上下文:按业务领域划分
│ │ ├── Ordering/ # 订单域
│ │ │ ├── Domain/ # 领域模型、值对象、领域事件
│ │ │ │ ├── Model/
│ │ │ │ ├── Events/
│ │ │ │ └── Spec/
│ │ │ ├── Application/ # 应用服务、DTO
│ │ │ ├── Infrastructure/ # 仓储实现、外部API适配
│ │ │ └── UserInterface/ # 控制器、API端点
│ │ ├── Payment/ # 支付域
│ │ │ └── ...
│ │ └── Inventory/ # 库存域
│ ├── Shared/ # 共享内核(通用工具类、基类)
│ └── ...
├── tests/
├── config/
└── ...
优点:高内聚低耦合,每个领域独立演进,适合微服务架构的代码库。 缺陷:初学时略显过重。
模块化/微服务单体(Modular Monolith)
将大型应用拆分为多个独立的“模块”,每个模块内部有自己的完整分层,这在框架中很常见。
project-root/
├── modules/
│ ├── User/
│ │ ├── Controllers/
│ │ ├── Models/
│ │ ├── Services/
│ │ ├── Repositories/
│ │ ├── Tests/
│ │ └── routes.php
│ ├── Product/
│ │ └── ...
│ └── Order/
│ └── ...
├── app/ # 全局公共代码
│ ├── Providers/
│ ├── Exceptions/
│ └── ...
├── config/
├── routes/
└── public/
优点:代码组织清晰,团队可独立负责不同模块,未来容易拆分为微服务。
命令行CLI工具或包(Packagist)类库
如果你在开发一个Composer包或CLI工具,结构应尽可能简单、可复用。
project-root/
├── src/
│ ├── Command/ # 命令类
│ ├── Exception/ # 异常
│ ├── Helper/ # 辅助函数
│ ├── Interface/ # 接口
│ └── YourPackage.php # 入口类
├── tests/
├── config/
├── bin/ # CLI入口脚本
├── composer.json
└── README.md
推荐的命名空间映射(基于方案一)
在composer.json中配置PSR-4的自动加载,一般指向app/或src/目录:
{
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
}
}
在这个配置下,类文件app/Services/OrderService.php的命名空间应为namespace App\Services;。
几个常见坑与建议
- 不要把所有逻辑都塞进Model:Model(如
User)不应包含发送邮件、生成PDF等与自身无关的逻辑,这会形成“肥胖模型”。- ✅ 推荐:将特定逻辑放入
Service或Action类。
- ✅ 推荐:将特定逻辑放入
- 避免过度嵌套:如
app/Http/Controllers/Api/V1/User/Auth/AuthController.php,当目录层级超过4层时,可考虑用模块化(如modules/Auth/)来扁平化。 - 使用
traits/目录:如果发现多个类共享相同的方法,可以考虑创建一个app/Traits/目录存放trait文件。 - 参考成熟框架:Laravel、Symfony、ThinkPHP等框架已经给出了很好的范例,如果使用框架,尽量遵循其默认约定(如Laravel的
app/Http/Controllers),不要随意重构。
总结建议
- 小项目(<10个文件):直接放在
lib/或src/根目录下即可。 - 中型项目(API、CMS):优先选择分层架构(Controller → Service → Model/Repository),清晰易维护。
- 大型复杂业务系统:可考虑DDD或模块化。
- 关键步骤:务必在项目初期配置好
composer.json的PSR-4自动加载,确保目录结构变动时能自动生效。