简介
本规范面向 DouPHP 项目的后端 PHP、前端模板与静态资源,目标是统一编码风格、命名约定、模块职责、SQL 编写、错误处理与日志记录标准,并提供可执行的代码审查清单与自动化检查建议。文档基于仓库现有实现进行归纳,确保规范与既有代码一致且可落地执行。
更新 新增导航和页面事实约定章节,明确$route_module和$route_action变量的语义分离原则,替代旧的$cur变量使用方式。
项目结构
DouPHP 采用"入口 + 核心框架 + 三端(前台 front、后台 admin、API)+ 主题与插件"的分层组织方式:
- 根入口 index.php 负责初始化引导、路由委派与全局异常处理。
- core 提供框架能力(自动加载、容器、HTTP、ORM、服务、支持类等)。
- config 集中管理应用配置(数据库、路径、调试开关等)。
- front/admin/api 为三个独立入口域,各自包含 controller、service、model、request、route、middleware、init 等分层目录。
- theme/newtheme/miniprogram 分别承载前台主题、新主题与小程序前端资源。
- plugin 存放第三方或业务插件。
- storage 用于运行时数据与缓存。
graph TB
A["入口 index.php"] --> B["引导 core/bootstrap.php"]
B --> C["配置 config/config.php"]
B --> D["自动加载 core/autoload.php"]
A --> E["前台 front/*"]
A --> F["后台 admin/*"]
A --> G["API api/*"]
E --> H["主题 theme/* / newtheme/*"]
F --> I["管理界面视图 admin/view/*"]
G --> J["API 响应与中间件"]
图示来源
- index.php:1-75
- core/bootstrap.php:15-180
- config/config.php:15-53
- core/autoload.php:18-114
章节来源
- index.php:1-75
- core/bootstrap.php:15-180
- config/config.php:15-53
- core/autoload.php:18-114
核心组件
- 入口与引导
- index.php:设置路由委派、解析语言前缀、启动 Init、分发路由、统一捕获异常并输出 JSON 或页面提示。
- core/bootstrap.php:定义常量、加载配置、注册自动加载、别名、DI 容器、Request/Router 单例、助手函数与事件注册器。
- 自动加载与命名空间映射
- core/autoload.php:实现 Dou\ 命名空间的自动加载规则,覆盖插件、Core、端侧(Admin/Front/Api)、Vendor 与兜底映射。
- 控制器基类
- admin/controller/BaseController.php:后台控制器基类,封装 view()、布局变量注入、删除结果响应、布尔切换响应等。
- api/controller/BaseController.php:API 控制器基类,复用前台用户中心导航构建逻辑。
- front/controller/BaseController.php:前台控制器基类,提供页面事实变量统一处理和导航构建。
- 模型通用修改器
- core/model/concerns/ContentMutators.php:内容模型的字段写入时标准化(标题、slug、关键词、描述、排序、时间、价格等)。
章节来源
- index.php:1-75
- core/bootstrap.php:15-180
- core/autoload.php:18-114
- admin/controller/BaseController.php:30-370
- api/controller/BaseController.php:24-60
- front/controller/BaseController.php:38-184
- core/model/concerns/ContentMutators.php:21-111
架构总览
请求从入口进入,经引导初始化后由路由分发到对应端(front/admin/api)的控制器,控制器调用服务层与模型层完成业务逻辑,最终通过统一的响应对象返回 JSON 或视图。
sequenceDiagram
participant U as "客户端"
participant R as "入口 index.php"
participant B as "引导 bootstrap.php"
participant RT as "路由 Router"
participant C as "控制器 Controller"
participant S as "服务 Service"
participant M as "模型 Model"
participant V as "视图/响应"
U->>R : HTTP 请求
R->>B : 初始化常量/配置/自动加载
B-->>R : 可用 Request/Router/容器
R->>RT : 设置委派并分发
RT->>C : 调用具体控制器方法
C->>S : 执行业务逻辑
S->>M : 读写数据
M-->>S : 数据对象
S-->>C : 业务结果
C->>V : 构造响应(ViewResponse/ApiResponse)
V-->>U : 返回响应
图示来源
- index.php:26-75
- core/bootstrap.php:115-180
- admin/controller/BaseController.php:60-68
- api/controller/BaseController.php:38-60
详细组件分析
入口与引导流程
- 入口职责
- 设置路由委派、解析语言前缀、启动 Init、分发路由、统一捕获异常并输出 JSON 或页面提示。
- 引导职责
- 定义常量、加载配置、注册自动加载、别名、DI 容器、Request/Router 单例、助手函数与事件注册器。
flowchart TD
Start(["进程启动"]) --> Boot["加载 bootstrap.php"]
Boot --> Config["读取 config/config.php"]
Config --> Autoload["注册自动加载与别名"]
Autoload --> DI["初始化容器与单例"]
DI --> Entry["入口 index.php 继续"]
Entry --> Route["设置路由委派并分发"]
Route --> Handle["捕获异常并输出响应"]
Handle --> End(["结束"])
图示来源
- core/bootstrap.php:15-180
- config/config.php:15-53
- index.php:26-75
章节来源
- index.php:1-75
- core/bootstrap.php:15-180
- config/config.php:15-53
自动加载与命名空间约定
- 命名空间与目录映射
- Dou\Plugin* -> plugin//src/ 或 plugin/*
- Dou\Core* -> core/*
- 端侧 Dou\Admin|Front|Api 下的 Init/Lib/Middleware/Http/Controller/Model/Service/Request/Facade/Foundation/Contract 按层映射到对应目录
- Dou\Vendor* -> core/library/{package}/...
- 模块类映射
- 根据已安装模块动态生成 ClassMap,提升加载效率。
classDiagram
class 自动加载器 {
+注册Dou命名空间
+解析插件类
+解析Core类
+解析端侧类
+解析Vendor类
+兜底映射
}
class 插件类 {
+Dou\\Plugin\\*
}
class Core类 {
+Dou\\Core\\*
}
class 端侧类 {
+Dou\\{Admin|Front|Api}\\*
}
class Vendor类 {
+Dou\\Vendor\\*
}
自动加载器 --> 插件类 : "优先匹配"
自动加载器 --> Core类 : "次级匹配"
自动加载器 --> 端侧类 : "按层映射"
自动加载器 --> Vendor类 : "库适配"
图示来源
- core/autoload.php:18-114
- core/autoload.php:140-204
- core/autoload.php:234-273
章节来源
- core/autoload.php:18-114
- core/autoload.php:140-204
- core/autoload.php:234-273
控制器基类与响应模式
- 后台控制器基类
- 提供 view() 渲染 ViewResponse,合并布局变量与 AI 工具栏配置。
- 提供 respondDeleteResult() 统一删除结果响应(302 + flash 或二次确认页)。
- 提供 respondToggle() 统一布尔切换响应(JSON 或 302 + flash)。
- API 控制器基类
- 复用前台用户中心导航构建逻辑,保持 API 与前台一致的导航 ViewModel。
- 前台控制器基类
- 提供 pageFactVars() 统一处理页面事实变量,包括导航列表、cur、route_module、route_action。
- 强制区分导航高亮(cur)和内容分支(route_module/route_action)的使用场景。
classDiagram
class 后台控制器基类 {
+view(template, data, status)
-absolutizeActionUrls(data)
-injectAiToolbar(data)
-isAiMountableModule(module)
+layoutVars()
-normalizeFlashes(rawAll)
-normalizeOne(raw)
+respondDeleteResult(result)
+respondToggle(request, value, message, backUrl)
+buildLinkUserCenter(currentModule)
}
class API控制器基类 {
+buildLinkUserCenter(currentModule)
}
class 前台控制器基类 {
+pageFactVars(merged)
+view(template, data, statusCode)
+layoutVars()
+respond(request, redirectUrl, data, message)
+buildLinkUserCenter(currentModule)
}
后台控制器基类 <|-- 具体后台控制器
API控制器基类 <|-- 具体API控制器
前台控制器基类 <|-- 具体前台控制器
图示来源
- admin/controller/BaseController.php:30-370
- api/controller/BaseController.php:24-60
- front/controller/BaseController.php:38-184
章节来源
- admin/controller/BaseController.php:30-370
- api/controller/BaseController.php:24-60
- front/controller/BaseController.php:38-184
导航和页面事实约定
新增 本节详细说明$route_module和$route_action变量的语义分离原则,以及新的导航高亮机制。
- 页面事实变量处理
- route_module:当前页命中的稳定路由模块名,用于内容分支判断(如区分不同宿主页面)。
- route_action:当前页命中的稳定路由动作名,用于细粒度内容控制。
- cur:由 NavigationBuilder::middle() 解析出的归属模块,专用于菜单高亮判断。
- 导航高亮机制
- 禁止使用$route_module/$route_action进行菜单高亮判断。
- 菜单高亮必须通过 NavigationBuilder 计算的布尔值或使用 cur 变量。
- NavigationBuilder 会自动从 request()->routeModule() 获取当前模块作为默认值。
- 变量注入顺序
- action data > layoutVars() > pageFactVars() 兜底值。
- 保证存量手写值的控制器在清理批次前后行为均不受影响。
flowchart TD
A["控制器 action 返回 $data"] --> B["合并 layoutVars()"]
B --> C["pageFactVars() 处理"]
C --> D{"是否已有 nav_top_list?"}
D --> |否| E["NavigationBuilder::top()"]
D --> |是| F["跳过"]
C --> G{"是否已有 nav_middle_list?"}
G --> |否| H["NavigationBuilder::middle()"]
G --> |是| I["跳过"]
C --> J{"是否已有 cur?"}
J --> |否| K["NavigationBuilder::contextModule()"]
J --> |是| L["跳过"]
C --> M{"是否已有 route_module?"}
M --> |否| N["request()->routeModule()"]
M --> |是| O["跳过"]
C --> P{"是否已有 route_action?"}
P --> |否| Q["request()->routeAction()"]
P --> |是| R["跳过"]
E --> S["最终模板变量"]
I --> S
K --> S
N --> S
Q --> S
图示来源
- front/controller/BaseController.php:81-109
- front/service/nav/NavigationBuilder.php:72-90
章节来源
- front/controller/BaseController.php:63-109
- front/service/nav/NavigationBuilder.php:58-90
模型字段修改器(ContentMutators)
- 统一字段写入时的清洗与类型转换,避免脏数据入库。
- 支持的字段包括:标题、slug、定义项、关键词、描述、排序、添加时间、价格、促销价等。
flowchart TD
In(["写入字段值"]) --> Type{"字段类型"}
Type --> |标题/Slug| Trim["去除首尾空白"]
Type --> |定义项| Replace["替换换行为逗号"]
Type --> |关键词/描述| Cast["强制字符串"]
Type --> |排序| Numeric["数值化或空串"]
Type --> |添加时间| ParseTime["strtotime 转时间戳"]
Type --> |价格/促销价| TrimPrice["去除空白"]
Trim --> Out(["标准化后的值"])
Replace --> Out
Cast --> Out
Numeric --> Out
ParseTime --> Out
TrimPrice --> Out
图示来源
- core/model/concerns/ContentMutators.php:21-111
章节来源
- core/model/concerns/ContentMutators.php:21-111
依赖关系分析
- 入口依赖引导与配置
- index.php 依赖 bootstrap.php 提供的常量、自动加载、容器与助手;依赖 config/config.php 中的数据库与路径配置。
- 引导依赖自动加载与别名
- bootstrap.php 注册自动加载与别名,使后续控制器、服务、模型可按命名空间加载。
- 控制器依赖服务与模型
- 控制器通过门面/助手调用服务与模型,遵循分层解耦。
- 前台控制器依赖导航构建器
- 前台控制器基类依赖 NavigationBuilder 进行导航数据构建和上下文模块解析。
graph LR
Index["index.php"] --> Bootstrap["bootstrap.php"]
Bootstrap --> Config["config/config.php"]
Bootstrap --> Autoload["autoload.php"]
Index --> Router["路由分发"]
Router --> Controllers["控制器"]
Controllers --> Services["服务"]
Services --> Models["模型"]
FrontControllers["前台控制器"] --> NavBuilder["NavigationBuilder"]
NavBuilder --> Request["Request"]
图示来源
- index.php:1-75
- core/bootstrap.php:15-180
- config/config.php:15-53
- core/autoload.php:18-114
- front/controller/BaseController.php:83-94
章节来源
- index.php:1-75
- core/bootstrap.php:15-180
- config/config.php:15-53
- core/autoload.php:18-114
性能考量
- 自动加载优化
- 使用 ClassMap 对已安装模块类进行预注册,减少文件系统探测开销。
- 单例与懒加载
- Request、Router、容器等在引导阶段以单例形式注册,避免重复构造。
- 响应最小化
- 控制器统一返回 ViewResponse/ApiResponse,减少冗余数据处理。
- 配置一次性加载
- module.php 在引导阶段统一读取并序列化,供多处复用,降低 IO 次数。
- 导航缓存优化
- NavigationBuilder 使用静态缓存避免重复数据库查询,提升导航构建性能。
故障排查指南
- 未安装跳转
- 若 storage/install.lock 不存在,非安装路径的请求将被重定向至安装程序。
- 全局异常处理
- 入口捕获 DomainException、HttpResponseException、RedirectException 与普通 Exception/Throwable,按 site.debug 与 JSON 协商输出调试页或 JSON 500。
- 日志记录
- 未捕获异常会写入 error_log,便于定位问题。
- 导航高亮问题
- 如果菜单高亮不正确,检查是否使用了$route_module/$route_action进行高亮判断,应改用 cur 变量或 NavigationBuilder 计算结果。
章节来源
- core/bootstrap.php:42-57
- index.php:38-75
- index.php:90-125
结论
DouPHP 通过清晰的入口引导、严格的命名空间自动加载、分层控制器基类与统一的响应模式,构建了可扩展、易维护的代码体系。配合 ContentMutators 的数据清洗与全局异常处理,项目在稳定性与一致性方面具备良好基础。新增的导航和页面事实约定进一步明确了$route_module/$route_action与cur变量的语义分离,提升了代码的可维护性和可读性。建议在团队中严格执行本规范,并结合自动化检查工具保障代码质量。
附录:检查清单与工具配置
PHP 代码风格与 PSR 遵循
- 命名空间与自动加载
- 所有类必须位于 Dou\ 命名空间下,并按 autoload.php 约定的目录结构放置。
- 缩进与括号
- 使用 4 空格缩进;控制结构与函数大括号遵循 PSR-12 风格。
- 注释格式
- 文件头部保留版权与协议注释;类与方法使用结构化注释(含参数与返回值说明)。
- 常量与配置
- 应用常量集中在 bootstrap.php 与 config/config.php 中定义,避免硬编码。
目录结构与模块职责
- 三端分层
- controller:接收请求、编排服务、返回响应。
- service:业务逻辑与跨模块协作。
- model:数据访问与字段修改器。
- request:输入校验与参数绑定。
- route:路由定义。
- middleware:横切关注点(鉴权、限流、安全头)。
- init:端侧初始化与容器绑定。
- 主题与插件
- theme/newtheme:前台主题资源与模板。
- plugin:插件按包隔离,遵循 Dou\Plugin* 命名空间。
命名约定
- 类名:StudlyCase(如 BaseController、ContentMutators)。
- 方法名:camelCase(如 layoutVars、respondDeleteResult)。
- 变量名:camelCase(如 $statusCode、$backUrl)。
- 常量:UPPER_SNAKE_CASE(如 ROOT_PATH、DOU_DEBUG)。
- 文件名:与类名一致(如 BaseController.php)。
导航和页面事实变量约定
新增 本节规定$route_module、$route_action和cur变量的使用规范。
- 变量语义分离
- route_module:仅用于内容分支判断,如区分不同宿主页面的展示逻辑。
- route_action:仅用于细粒度的内容控制,如特定动作的特殊处理。
- cur:专用于菜单高亮判断,由 NavigationBuilder 计算得出。
- 禁止事项
- 禁止使用$route_module/$route_action进行菜单高亮判断。
- 禁止在模板中直接比较$route_module/$route_action进行导航状态判断。
- 正确用法示例
- 内容分支:
if ($route_module === 'product') { ... } - 菜单高亮:
if ($cur === 'product') { ... }或使用 NavigationBuilder 计算的布尔值
- 内容分支:
SQL 查询编写规范
- 使用 ORM 或查询构建器,避免拼接原始 SQL。
- 参数化查询,防止注入。
- 分页与索引:列表查询需考虑分页与必要索引。
- 事务:涉及多表写操作时使用事务保证一致性。
错误处理模式
- 控制器抛出领域异常或返回统一响应对象。
- 入口统一捕获并输出 JSON 或页面提示。
- 日志:关键错误记录 error_log,便于追踪。
日志记录标准
- 使用 error_log 记录未捕获异常与关键业务事件。
- 敏感信息脱敏后再记录。
- 区分环境:生产环境关闭调试输出,仅记录必要日志。
前端代码规范(JavaScript/CSS/模板)
- JavaScript
- 模块化:按功能拆分脚本,避免全局污染。
- 命名:camelCase 变量与函数,PascalCase 构造函数。
- 异步:统一使用 Promise/async-await 处理异步逻辑。
- CSS
- 选择器语义化,避免深层嵌套。
- 变量与主题:使用 CSS 变量管理颜色与尺寸。
- 模板文件
- .dwt/.htm:仅展示逻辑,不包含复杂业务计算。
- 变量输出需转义,防止 XSS。
- 导航高亮:使用 cur 变量而非$route_module/$route_action。
代码审查检查清单
- 是否遵循命名空间与自动加载约定?
- 控制器是否只编排服务与返回响应?
- 服务层是否包含完整业务逻辑?
- 模型是否使用修改器清洗字段?
- 是否使用参数化查询与事务?
- 是否统一异常处理与日志记录?
- 前端模板是否仅负责展示?
- 是否通过自动化检查(Lint/格式化)?
- 新增 导航高亮是否正确使用 cur 变量而非$route_module/$route_action?
- 新增 内容分支是否正确使用$route_module/$route_action?
自动化检查工具配置建议
- PHP
- 使用 PHP_CodeSniffer 或 PHP CS Fixer 配置 PSR-12 规则。
- 在 Git Hooks 或 CI 中强制执行。
- 前端
- ESLint + Prettier 统一 JS 风格。
- Stylelint 检查 CSS。
- 模板
- 模板变量输出转义检查(结合 Lint 规则)。
- 新增 导航变量使用检查:检测模板中是否误用$route_module/$route_action进行高亮判断。