PHP无官方MVC目录标准,vendor/必须在根目录因Composer自动加载机制限定;public/为唯一Web可访问目录,其余目录须置于其外并禁止URL访问;配置应使用环境变量而非硬编码,路由与控制器需严格遵循PSR-4命名规范。

PHP没有官方MVC目录结构标准,所谓“标准”其实是社区长期演进形成的共识,不是语言强制要求,硬套反而容易卡在路由或自动加载上。
为什么 vendor/ 必须放在项目根目录下
Composer 的 autoload 和 vendor/autoload.php 默认只认项目根目录下的 vendor/。如果把它挪到 app/vendor/ 或 src/vendor/,require 'vendor/autoload.php' 会直接报错 Warning: require(vendor/autoload.php): failed to open stream。
- 所有现代 PHP 项目(Laravel、Symfony、Slim)都把
vendor/放在根目录,不是习惯,是 Composer 设计使然 - 你可以在
composer.json里改"vendor-dir",但后续部署、CI、Docker 构建全得同步适配,不值得 - 别为了“看起来整齐”把
vendor/塞进子目录——它本来就不该被你手动编辑或提交到 Git
public/ 是唯一该暴露给 Web 服务器的目录
Web 服务器(Nginx/Apache)的 root 或 DocumentRoot 必须指向 public/,否则 index.php 外的任何 PHP 文件(比如 app/Controller/HomeController.php)可能被直接下载或执行,造成源码泄露或 RCE。
-
public/index.php是唯一入口,它负责引入自动加载、初始化容器、分发请求 -
app/、config/、database/这些目录必须在public/外层,且 Web 服务器无法通过 URL 访问到 - Nginx 配置里别漏掉
try_files $uri $uri/ /index.php?$query_string;,否则路由伪静态失效
config/ 下的文件不能直接 return 数组就完事
很多新手写 config/database.php 直接 return ['driver' => 'mysql', ...];,看似能用,但环境切换(dev/staging/prod)时立刻崩:密码、host、debug 开关全得硬编码改文件。
立即学习“PHP免费学习笔记(深入)”;
- 用
getenv()或$_ENV读取环境变量,再 fallback 到默认值,例如:$_ENV['DB_HOST'] ?? '127.0.0.1' - 把敏感配置抽到
.env(用vlucas/phpdotenv加载),.env不提交 Git,不同环境部署不同版本 - 别在 config 文件里做复杂逻辑(如条件判断加载不同驱动),配置就该是纯数据,逻辑交给服务提供者或引导文件
routes/ 和 controllers/ 的耦合点常被忽略
路由定义(比如 routes/web.php)和控制器类路径之间,靠的是 PSR-4 自动加载规则 + 手动命名约定。一旦命名不一致,Class AppControllersHomeController not found 就来了。
- 确保
composer.json的autoload.psr-4正确映射:"App\": "app/",且控制器文件路径严格匹配命名空间,如app/Controllers/HomeController.php→namespace AppControllers; - 路由闭包里写
new HomeController()是反模式,应通过容器解析,否则依赖无法注入 - 别把路由逻辑塞进控制器方法里(比如在
index()里判断$_GET['type']),那是路由职责,不是控制器的
真正卡住人的从来不是“该放几个目录”,而是哪一层该读环境变量、谁负责实例化控制器、自动加载失败时错误信息藏在哪一行——这些细节没对齐,结构再“标准”也跑不起来。



















