无框架 PHP 项目结构设计:单入口 MVC 的目录规划
无框架 PHP 项目的单入口 MVC,目录规划只要守住三条线就不会翻车:所有 HTTP 请求收进唯一的 index.php,代码/配置/可写数据三者物理分离,一次性入口(安装向导、升级脚本)与常驻入口隔离。下面这套骨架,Clara BBS 这类无框架 PHP 系统就是按这个思路走的,可以直接抄。
为什么必须是单入口:只做一次初始化
结论:单入口不是为了架构好看,而是为了让数据库连接、会话、身份校验、CSRF token、错误处理这些事只做一次。
如果把 db.php、session.php 散在各个页面顶部 include,三五个页面之后就会出现"某个页面忘了校验登录"的洞。单入口的写法是:index.php 里只做三件事——加载 bootstrap、解析路由、分发到控制器。bootstrap 负责初始化,控制器只管业务,其它入口(比如后台、命令行脚本)复用同一个 bootstrap。
服务器侧也因此变得极简:只要把非静态文件的请求转发到 index.php 即可(Nginx 用 try_files,Apache 用 .htaccess)。Clara BBS 会自动识别 .html 后缀 URL,服务器不需要再写任何伪静态规则——这是单入口白送的红利。
注意点:转发规则里必须放行静态目录,否则一张图片、一个 CSS 都要绕一圈 PHP,白白吃掉性能。
骨架:一份可直接抄的目录结构
结论:可写目录、代码目录、入口文件必须分开放,代码目录不要直接暴露在 Web 根下。
/index.php ← 唯一 HTTP 入口
/install/ ← 安装向导,装完删除或改名
/app/
/controller/ ← 控制器
/model/ ← 数据访问
/view/ ← 视图模板
/library/ ← 公共类:分页、上传、验证码
/config/ ← 配置,禁止外部访问
/content/
/plugins/ ← 插件,运行时钩子加载
/uploads/ ← 用户上传,需可写
三条落地原则:入口目录下只留 index.php 和 install;app/ 里全是类文件,不允许任何直接输出;content/ 和 uploads/ 是唯一允许写入的目录,权限给它,其它目录保持只读。
视图层只负责输出,不查库不判断
结论:视图文件里出现 SQL 或复杂的 if 分支,说明分层已经破了。
无框架项目最常见的退化就是从视图开始——"就差一个字段,顺手查一下吧"。正确做法是控制器把数据备齐,视图只做循环和转义输出。输出转义是 XSS 的底线,凡是用户填的内容(标题、回帖、昵称)进模板时必须转义。
另外,单模板响应式的做法是用一套 view 文件 + CSS 媒体查询同时适配手机和桌面,不要搞 m 站/PC 站两套模板,那意味着所有页面都要维护两份。
插件放 content/plugins,扩展点用钩子
结论:所有扩展都走运行时钩子,绝不直接改核心文件,否则下次升级覆盖文件时全丢。
插件目录独立在 content/plugins 下,由运行时钩子体系挂载。好的设计是保存即生效,不需要编译、不需要清缓存——Clara BBS 的钩子体系有 156 个挂载点,正是这个模式。反面教材是"我就改这一行",改完当时能用,升级时被整包覆盖。
不用 Composer 时的自律:自己写自动加载
结论:没有 Composer 就注册一个 spl_autoload_register 回调,把命名空间映射到 app/ 目录,类名和文件名严格一一对应。
环境上 PHP 7.4 到 8.5 都能跑,不需要命令行、不需要构建步骤。既然没有编译缓存,就别引入代码生成那一套——生成的中间文件既难排查又容易被误提交。配置文件用纯 PHP 数组返回,比解析 ini/json 更省事,也不会有格式歧义。
上线前检查清单
- install 目录装完立即删除或改名,别留着当后门;
- uploads 可写,上传走扩展名白名单 + 文件类型二次校验;
- 数据库结构变更写成幂等的增量脚本,执行一次即可,重复执行不报错(Clara BBS 放在后台「系统工具→数据库升级」里,覆盖文件后跑一次就补齐新字段);
- 定时任务做成懒触发,不用额外配 crontab;
- 入口文件里关闭错误回显、打开日志。
单入口 MVC 的目录规划说到底就是把"请求收口、数据分离、扩展走钩子"这三件事做成硬约束。骨架搭对了,后面加功能是往里塞文件;骨架搭错了,每加一个功能都在补漏。
转载请注明出处,版权归原作者所有。
星耀SVIP
管理员
黑卡会员





