【中国观察北京时间2026年08月16日】
PHP 项目的目录结构没有一套适用于所有项目的固定标准。一个几十个页面的小型网站,与拥有后台、API、队列、缓存和多个业务模块的大型系统,需要解决的问题完全不同。
真正合理的目录规划,不是目录越多越专业,而是让代码、配置、第三方依赖、用户上传文件和运行时数据各自放在合适的位置,并且随着项目规模扩大,可以逐步增加结构,而不需要频繁推倒重来。
对于普通 PHP 开发者来说,可以按照项目规模,从简单结构开始,再逐步引入分层、模块化等设计。
一、最简单的网站不需要复杂目录
如果只是一个简单的 PHP 网站,例如几个页面、一个数据库和少量 CSS、JavaScript,完全没有必要一开始就采用复杂的 MVC 或模块化结构。
可以使用类似这样的目录:
mywebsite/
├── index.php
├── about.php
├── contact.php
├── config/
│ └── database.php
├── includes/
│ ├── header.php
│ ├── footer.php
│ └── functions.php
├── css/
│ └── style.css
├── js/
│ └── main.js
└── images/
这种结构的重点不是形式,而是把不同类型的文件分开。
页面文件负责页面展示和简单流程。
config 存放配置。
includes 存放可以重复使用的 PHP 文件。
css、js 和 images 分别保存前端资源。
对于一个小型网站,这样已经足够。
如果项目只有十几个 PHP 文件,没有必要为了所谓的专业性建立十几个目录。
二、项目开始变复杂以后,再引入 public
当 PHP 项目包含越来越多的业务代码以后,一个非常有价值的变化是把网站的 Web 根目录与内部代码分开。
例如:
mywebsite/
├── public/
│ ├── index.php
│ ├── css/
│ ├── js/
│ └── images/
│
├── app/
│ ├── Controllers/
│ ├── Models/
│ ├── Services/
│ └── Views/
│
├── config/
├── storage/
├── database/
├── vendor/
├── composer.json
└── composer.lock
这里最重要的变化是:
Web 服务器的 DocumentRoot 指向 public/,而不是整个项目目录。
这样浏览器可以直接访问 public 中需要公开的文件,而数据库配置、业务代码、Composer 依赖等内容不会因为 Web 服务器配置错误而直接暴露。
这是一种非常实用的安全边界。
三、app 目录负责应用代码
当项目进入中等规模以后,可以把主要业务代码集中到 app。
例如:
app/
├── Controllers/
├── Models/
├── Services/
├── Views/
└── Middleware/
不同目录承担不同职责。
Controllers 负责接收请求、调用业务逻辑并决定返回什么结果。
Models 负责与数据模型或数据库相关的操作。
Services 用于放置比较复杂的业务逻辑。
Views 负责页面模板。
Middleware 可以处理身份认证、权限检查等请求前后的公共逻辑。
这里需要注意,MVC 并不是要求所有 PHP 项目必须严格按照某一种目录命名。不同框架和团队可能采用不同结构。
目录结构的目的,是帮助开发者保持职责清晰,而不是为了满足某个固定模板。
四、为什么不应该把所有代码都放进 Controller
随着项目增长,一个常见问题就是 Controller 越来越大。
例如用户注册:
Controller
↓
验证用户输入
↓
检查邮箱
↓
创建用户
↓
发送邮件
↓
记录日志
如果这些工作全部写在 Controller 里,文件很快就会变得难以维护。
因此,可以把复杂业务逻辑移动到 Service:
app/
├── Controllers/
│ └── UserController.php
│
├── Services/
│ └── UserService.php
│
└── Models/
└── User.php
Controller 负责处理请求。
Service 负责业务流程。
Model 负责数据相关操作。
这样做并不是为了增加目录,而是为了避免一个 PHP 文件承担过多职责。
五、config 应该放什么
config 通常用于保存应用程序的配置,例如:
config/
├── app.php
├── database.php
└── mail.php
例如数据库配置可以读取环境变量:
return [
'host' => getenv('DB_HOST'),
'database' => getenv('DB_DATABASE'),
'username' => getenv('DB_USERNAME'),
'password' => getenv('DB_PASSWORD'),
];
真正的密码、API Key 等敏感信息不应该直接硬编码到 Git 仓库中的 PHP 文件里。
对于采用 .env 的项目,.env 通常应该加入 .gitignore。
需要特别区分:
配置代码与配置秘密不是一回事。
config/database.php 可以负责读取配置。
数据库密码则可以由环境变量提供。
六、database 目录适合存放数据库相关文件
如果项目需要数据库迁移、初始化数据或测试数据,可以建立:
database/
├── migrations/
└── seeders/
这里的 database 与 config 的作用不同。
config 负责配置。
database 可以保存数据库结构变化和初始化数据相关文件。
如果项目很小,只使用一个 SQL 文件,也没有必要为了目录结构而强行建立复杂的数据库体系。
七、storage 用来保存运行过程中产生的数据
项目运行以后可能产生日志、缓存、临时文件或者用户上传文件。
可以考虑:
storage/
├── logs/
├── cache/
├── temp/
└── uploads/
这样可以把源代码与运行过程中产生的数据区分开。
不过,用户上传文件是否放在 storage,还要看项目的部署方式。
如果上传文件必须直接通过浏览器访问,也可以把它放在公开目录下,例如:
public/uploads/
如果上传文件包含身份证、合同等不应该被直接访问的敏感资料,则不应该简单地放在 Web 可公开访问的目录中。
因此,目录规划还需要考虑文件本身的访问权限。
八、vendor 不应该自己维护
使用 Composer 的 PHP 项目通常会出现:
vendor/
composer.json
composer.lock
vendor 是 Composer 安装第三方依赖的目录。
开发者一般不需要手工修改里面的代码。
通常情况下,vendor/ 不提交到 Git,而是提交:
composer.json
composer.lock
然后在新的开发机或服务器上通过 Composer 安装依赖。
这样可以避免把大量第三方代码直接作为项目源码维护。
九、前端资源应该放在哪里
对于传统 PHP 网站,可以采用:
public/
├── css/
├── js/
├── images/
└── fonts/
这样浏览器需要访问的静态资源都位于 public。
如果项目使用 React、Vue 等独立前端,则目录结构可能完全不同。
例如前后端分离项目可能是:
project/
├── backend/
└── frontend/
因此,不能简单地说 PHP 项目一定必须有 frontend 目录。
应该根据项目实际架构决定。
十、API 不一定需要单独建立一个完整项目
如果 PHP 网站同时提供 API,可以根据规模选择不同方式。
小型项目可以直接:
app/
└── Controllers/
├── WebController.php
└── ApiController.php
也可以进一步组织:
app/
├── Http/
│ ├── Controllers/
│ ├── Middleware/
│ └── Requests/
│
└── Services/
大型项目则可能按照 API 版本划分:
app/
└── Http/
└── Controllers/
└── Api/
├── V1/
└── V2/
因此,API 是否单独建立目录,应该由接口数量、版本管理和业务复杂度决定。
十一、项目越来越大以后,可以开始模块化
当一个系统拥有用户、文章、订单、支付、评论、后台管理等大量功能时,仅仅按照 Controllers、Models、Services 分类可能仍然会产生大量文件。
例如:
app/
├── Controllers/
│ ├── UserController.php
│ ├── NewsController.php
│ ├── OrderController.php
│ └── PaymentController.php
│
├── Models/
│ ├── User.php
│ ├── News.php
│ ├── Order.php
│ └── Payment.php
│
└── Services/
├── UserService.php
├── NewsService.php
├── OrderService.php
└── PaymentService.php
项目继续扩大后,可以考虑按照业务模块组织:
app/
├── Modules/
│ ├── User/
│ │ ├── Controllers/
│ │ ├── Models/
│ │ ├── Services/
│ │ └── Views/
│ │
│ ├── News/
│ │ ├── Controllers/
│ │ ├── Models/
│ │ ├── Services/
│ │ └── Views/
│ │
│ └── Payment/
│ ├── Controllers/
│ ├── Models/
│ └── Services/
这种方式的核心思想是让一个业务模块相关的代码尽量集中。
这样以后修改支付系统时,不需要在整个项目的几十个目录之间来回寻找相关代码。
十二、大型项目还需要考虑 Shared 和 Core
如果项目规模继续扩大,有些代码并不属于某一个具体业务模块。
例如:
app/
├── Core/
├── Shared/
└── Modules/
Core 可以放置系统核心能力。
Shared 可以放置多个模块共同使用的代码。
Modules 则保存具体业务。
但这两个目录并不是 PHP 官方规定的标准目录。
它们只是大型项目中常见的一种组织方式。
如果项目没有真正的共享代码,就没有必要为了形式建立 Shared。
十三、不要把 security 当成万能目录
安全功能通常分散在整个应用程序中。
例如:
Middleware
身份认证
Policy
权限判断
Validator
输入验证
Service
业务安全规则
Config
安全相关配置
因此,与其建立一个巨大的:
security/
不如根据代码实际承担的职责,把安全控制放到相应的位置。
真正重要的是权限检查、输入验证、会话管理、密码处理、CSRF 防护以及文件访问控制是否正确,而不是目录名字叫不叫 security。
十四、不要为了目录整齐而过度设计
一个 PHP 项目最常见的错误之一,就是过早建立复杂架构。
如果项目只有:
20 个 PHP 文件
却建立:
Core/
Domain/
Infrastructure/
Application/
Modules/
Services/
Repositories/
Factories/
Policies/
Middleware/
Providers/
最终可能不是更容易维护,而是开发者需要花大量时间寻找一个简单函数到底放在哪里。
因此可以遵循一个非常实际的原则:
项目有问题,再增加结构。
小项目先简单。
代码开始重复,再抽取公共代码。
Controller 开始变得复杂,再增加 Service。
模块开始互相混杂,再进行模块化。
项目出现多个环境,再完善配置管理。
不要为了想象中的未来,把今天的项目提前设计成一个巨型系统。
十五、一个比较均衡的中型 PHP 项目结构
如果需要一个既不过度复杂,又具有扩展能力的基础方案,可以采用:
project/
├── public/
│ ├── index.php
│ ├── css/
│ ├── js/
│ └── images/
│
├── app/
│ ├── Controllers/
│ ├── Models/
│ ├── Services/
│ ├── Middleware/
│ └── Views/
│
├── config/
│ ├── app.php
│ └── database.php
│
├── database/
│ ├── migrations/
│ └── seeders/
│
├── storage/
│ ├── logs/
│ ├── cache/
│ └── temp/
│
├── vendor/
│
├── .env
├── .gitignore
├── composer.json
└── composer.lock
这个结构已经能够覆盖大量传统 PHP 网站和中小型 Web 应用。
十六、大型项目应该从业务边界出发,而不是从目录数量出发
真正进入大型项目以后,目录规划的重点会从文件分类转向业务边界。
例如:
app/
├── Modules/
│ ├── User/
│ ├── Content/
│ ├── Order/
│ ├── Payment/
│ └── Administration/
│
├── Shared/
└── Core/
此时需要进一步考虑模块之间的依赖关系、数据库边界、接口、事件、缓存、队列以及权限系统。
如果某个模块已经发展成独立服务,也可以进一步拆分成独立应用。
但这一步应该建立在真实的业务规模和技术需求上,而不是因为大型项目看起来就应该使用微服务。
十七、目录规划最重要的其实只有几个原则
第一,Web 可访问文件与内部代码分开。
第二,配置与业务代码分开。
第三,敏感配置不要直接硬编码进源码。
第四,第三方依赖交给 Composer 管理。
第五,运行时产生的日志、缓存和临时文件不要与源代码混在一起。
第六,业务逻辑复杂以后再进行 Controller、Service、Model 等职责划分。
第七,项目真正变大以后,再考虑模块化。
第八,不要把某一种团队习惯误认为 PHP 官方标准。
一个好的 PHP 项目目录结构,并不是看起来有多少目录,而是当项目不断增加功能时,开发者仍然能够迅速找到代码、理解代码之间的关系,并且能够安全地修改和部署系统。
对于刚开始开发的项目,最好的目录结构往往不是最复杂的那个,而是当前足够清晰,同时允许未来自然扩展的那个。
换句话说,PHP 项目目录规划真正追求的不是复杂,而是边界清楚。随着项目从简单网站发展到中型应用,再发展到大型系统,目录结构也应该随实际需求逐步演进,而不是一开始就套上一套庞大的架构模板。
PHP 项目目录怎么规划?从简单网站到大型项目逐步建立结构
喜欢这篇报道?
使用下面的功能,方便以后继续阅读和分享 MNewsTV
关于文章收藏
收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。
删除收藏请进入「我的收藏」进行管理。
分享 Facebook | X | WhatsApp | LinkedIn
捐助(Paypal): https://www.paypal.me/observeccp 订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP