本文目录导读:

这是一个非常经典且重要的问题,合理的目录结构是项目可维护性、可扩展性和团队协作的基础。
PHP项目的目录结构没有绝对的“唯一标准”,但业界有一些经过大量实践检验的最佳实践模式,这里我会介绍几种最常见、最推荐的方案,并提供适用场景分析。
核心原则
在开始之前,请记住这几个核心原则:
- 约定优于配置:团队成员遵循统一的约定,减少沟通成本。
- 关注点分离:业务逻辑、数据访问、视图展示、公共配置要分开。
- 入口安全:Web 根目录只放置唯一的入口文件和静态资源,业务代码放在根目录之外,无法被直接访问。
- 可扩展性:便于后期添加新功能或模块。
基于框架的标准结构(最推荐)
这是基于现代框架(如 Laravel、Symfony、ThinkPHP、Yii2)的终极进化版。这是最推荐的方案,能帮你避免 99% 的坑。
project-root/
├── public/ # Web 服务器根目录(DocumentRoot)
│ ├── index.php # 单一入口文件
│ ├── .htaccess # Apache URL 重写规则(可选)
│ ├── nginx.conf.example # Nginx 重写规则示例(可选)
│ └── static/ # 静态资源(CSS、JS、图片等)
├── config/ # 配置文件
│ ├── app.php # 应用配置
│ ├── database.php # 数据库配置
│ ├── cache.php # 缓存配置
│ └── routes.php # 路由定义(或放在单独目录)
├── app/ # 核心业务代码
│ ├── Controllers/ # 控制器
│ │ ├── Admin/
│ │ └── Api/
│ ├── Models/ # 数据模型 / 实体
│ ├── Services/ # 业务逻辑层(领域服务)
│ ├── Repositories/ # 数据仓库层(数据访问抽象)
│ ├── Middleware/ # 中间件(权限验证、日志等)
│ ├── Exceptions/ # 自定义异常类
│ ├── Helpers/ # 辅助函数(有时放在全局)
│ └── Providers/ # 服务提供者(框架/DI 容器相关)
├── database/ # 数据库相关
│ ├── migrations/ # 迁移文件
│ └── seeds/ # 填充数据
├── resources/ # 视图 / 语言 / 未编译资源
│ ├── views/ # 视图模板文件(blade、twig、phtml 等)
│ ├── lang/ # 语言包(多语言支持)
│ └── assets/ # 未编译的前端资源(SCSS、Vue 组件等)
├── storage/ # 运行时文件(日志、缓存、上传文件等)
│ ├── logs/ # 日志文件
│ ├── cache/ # 缓存文件
│ └── app/ # 用户上传文件等(需做权限处理)
├── tests/ # 单元测试 / 功能测试
│ ├── Unit/
│ └── Feature/
├── vendor/ # Composer 依赖管理(自动生成,不要手动修改)
├── .env # 环境变量(不应提交到 Git)
├── .env.example # 环境变量示例(应提交到 Git)
├── composer.json # Composer 配置
├── composer.lock # Composer 版本锁定文件
├── package.json # 前端依赖(如使用 npm/yarn)
└── artisan / console # 命令行入口(如 artisan 或自定义 CLI 文件)
优点:
- 安全性极高:
public目录是唯一对外暴露的,任何对app/、config/、storage/的直接 URL 访问都会被服务器拒绝。 - 结构清晰:每一层都有明确的职责,便于团队多人协作。
- 生态丰富:直接适配 Laravel、Symfony 等主流框架的思想,学习资料海量。
- 可测试性:天然支持单元测试和功能测试。
适用场景:
- 任何中大型项目。
- 任何使用现代框架(Laravel、Symfony、ThinkPHP 6/8+)的项目。
- 任何需要长期维护、团队协作的项目。
轻量级 / 微服务结构
如果项目较小且不使用重型框架,或者使用 Slim、Lumen 等微框架。
project-root/
├── public/
│ └── index.php # 入口文件
├── src/ # 所有业务代码
│ ├── Controllers/
│ │ └── HomeController.php
│ ├── Models/
│ │ └── User.php
│ ├── Middleware/
│ ├── Routing/
│ └── Support/ # 辅助工具类
├── config/
│ └── app.php
├── views/ # 视图模板
├── storage/
├── tests/
├── vendor/
├── composer.json
└── .env
不同点:
- 去掉了
app目录,直接用src。 - 去掉了过多的分层(如没有强制
Services和Repositories)。 - 视图文件直接放在根目录下(或
resources/views)。
适用场景:
- 小型 API 项目或简单 Web 应用。
- 使用 Slim、Lumen、Flight 等微框架。
模块化 / DDD 结构(高级)
对于大型复杂业务系统,推荐领域驱动设计(DDD)的模块化。
project-root/
├── public/
├── modules/ # 业务模块
│ ├── User/ # 用户模块
│ │ ├── Controllers/
│ │ ├── Models/
│ │ ├── Services/
│ │ ├── Repositories/
│ │ └── Tests/
│ ├── Order/ # 订单模块
│ │ └── ...
│ └── Payment/ # 支付模块
│ └── ...
├── core/ # 核心基础设施
│ ├── BaseController.php
│ ├── BaseModel.php
│ └── Exceptions/
├── config/
├── database/
├── resources/
├── storage/
├── vendor/
└── composer.json
优点:
- 高内聚,低耦合:每个模块独立,模块间通过接口或事件通信。
- 团队独立:不同团队可以独立开发不同模块,互不影响。
- 可拆分为微服务:当项目变大后,可以轻松将某个模块抽取为单独的微服务。
适用场景:
- 大型、复杂、长期的业务系统(如电商、ERP、CRM)。
- 团队规模较大(10人以上)。
- 计划未来进行微服务拆分。
一些细节建议
-
public目录的权限- 配置 Web 服务器(Nginx/Apache)的
document root直接指向public目录。 - 永远不要将
index.php之外的 PHP 文件放在public目录下(除非是非常特殊的静态生成文件)。
- 配置 Web 服务器(Nginx/Apache)的
-
vendor目录- 永远不要手动修改
vendor内的文件。 - 将
vendor加入.gitignore文件。 - 在部署时运行
composer install --no-dev。
- 永远不要手动修改
-
storage目录- 确保
storage目录在运行时对 Web 服务器用户有写权限(如chmod -R 775 storage)。 - 将其加入
.gitignore(除了storage/.gitkeep占位文件)。
- 确保
-
配置文件
- 使用
.env文件存储敏感信息(数据库密码、API Key 等)。 - 在
.gitignore中加入.env文件。 - 提交一个
.env.example作为模板。
- 使用
-
命名空间 (Namespace) 与自动加载
- 使用 PSR-4 自动加载标准(通过 Composer 配置)。
- 命名空间与目录结构保持严格一致。
app/Controllers/Api/UserController.php的命名空间为App\Controllers\Api\UserController。
-
视图位置
- 主流框架通常将视图放在
resources/views中。 - 如果使用模板引擎(如 Smarty、Twig),编译后的缓存文件建议放在
storage/cache中。
- 主流框架通常将视图放在
如何选择?
| 项目类型 | 推荐结构 |
|---|---|
| 个人项目 / 学习 | 方案二(轻量级)或 直接使用 Laravel/ThinkPHP 默认结构 |
| 小型团队 / 中小型项目 | 方案一(框架标准结构) |
| 大型团队 / 复杂业务 | 方案一 + 模块化(方案三) |
| 微服务 | 每个微服务独立使用方案一 |
| 老旧项目 / 无框架 | 逐步重构到方案一,至少做好 public/ 目录隔离 |
一句话建议:直接使用一个现代框架(Laravel 或 ThinkPHP),并严格遵循它的默认目录结构。 这样做不仅省心,而且能直接利用社区的最佳实践和工具生态,如果你需要自己搭建结构,请严格遵循方案一,那已经是经过无数项目验证的黄金标准。