Skip to content

Stooland API 架构与最佳实践指南

本文档基于 Stooland API 项目的实际代码结构(ThinkPHP 8 多应用模式)以及现代 PHP 开发标准,总结了一套适用于本项目的架构规范与最佳实践。旨在帮助开发团队统一代码风格,提升代码的可维护性、扩展性和安全性。

1. 架构总览

本项目采用 ThinkPHP 8 多应用模式,遵循经典的分层架构设计:

mermaid
graph TD
    Request[客户端请求] --> Route[路由层 (route/router.php)]
    Route --> Middleware[中间件层 (middleware/)]
    Middleware --> Controller[控制器层 (controller/)]
    Controller --> Validate[验证层 (validate/)]
    Controller --> Service[服务层 (service/)]
    Service --> Model[模型层 (model/)]
    Service --> ThirdParty[第三方SDK (extend/)]
    Model --> Database[(数据库)]

核心分层职责

  • Controller (控制器): 仅负责 接收请求、参数校验(调用验证器)、调用 Service 处理业务、标准化响应格式。严禁 在控制器中编写复杂的业务逻辑或直接操作数据库。
  • Service (服务层): 核心业务逻辑的载体。负责编排业务流程、事务控制、调用 Model 或第三方服务。Service 应该是可复用的。
  • Model (模型层): 负责与数据库交互。包含数据表映射、关联关系定义、获取器/修改器、以及数据层面的简单逻辑(如 Scope 查询范围)。
  • Validate (验证层): 负责输入数据的格式和规则校验。
  • Logic (逻辑层/可选): 对于特别复杂的业务,可以在 Service 之上再抽象一层 Logic,或者作为 Service 的辅助组件。

2. 开发最佳实践

2.1 控制器 (Controller)

  • 继承基类: 所有 API 控制器应继承 app\base\controller\ApiBaseController,该基类封装了用户身份认证 (checkLogin)、上下文管理 (getMember, getActor) 和标准响应方法。
  • 保持“瘦”控制器: 控制器方法应尽可能简短。
  • 参数获取: 使用 $this->getParams('key', $default) 获取参数,避免直接使用 input()$_GET/$_POST
  • 标准响应: 必须使用 $this->sendResponse($code, $data, $msg) 返回结果,确保前端收到的 JSON 结构一致。

❌ 错误示例:

php
public function create() {
    $data = input('post.');
    // 业务逻辑混杂在控制器
    if ($data['age'] < 18) return json(['code'=>1, 'msg'=>'error']);
    Db::name('user')->insert($data); // 直接操作数据库
    return json(['code'=>0, 'data'=>'ok']);
}

✅ 正确示例:

php
public function create() {
    $params = $this->getParams();
    // 1. 验证
    $this->validate($params, 'User.create');
    // 2. 调用服务
    $result = $this->userService->createUser($params);
    // 3. 响应
    return $this->sendResponse(0, $result);
}

2.2 服务层 (Service)

  • 单一职责: 一个 Service 类应专注于一个领域的业务(如 VolcengineVisualService 专注视觉生成)。
  • 依赖注入: 推荐在 Service 中实例化 Model 或其他依赖,或者通过构造函数注入。
  • 事务管理: 涉及多个数据表更新的操作,务必在 Service 中使用 Db::transaction()
  • 避免直接输出: Service 方法只应返回数据或抛出异常,绝不 应该 echoreturn json()

💡 优化建议: 项目中存在如 VolcengineVisualService::submitTask 这样包含大量 if-else 判断不同 reqKey 的代码。建议使用 策略模式 (Strategy Pattern)工厂模式 进行重构,将每种任务类型的处理逻辑拆分到独立的处理器类中,提高可维护性。

2.3 模型层 (Model)

  • 使用 ORM: 优先使用 ThinkPHP 的模型方法(find, save, create)而非 Db::name()->insert(),以便利用模型的自动时间戳、获取器和事件机制。
  • 关联关系: 在模型中显式定义关联(hasOne, hasMany),避免在 Service 中手动拼装关联数据。
  • Scope 查询: 将常用的查询条件封装为 Scope(如 scopeActive),提高代码复用性。

2.4 异常处理 (Exception Handling)

  • 自定义异常: 业务错误应抛出 app\base\exception\SaasException 或其子类,而不是通用的 \Exception
  • 全局捕获: 框架的异常处理接管了所有未捕获异常,自动记录日志并返回标准错误 JSON。
  • 错误码: 使用 config/status.php (假设) 或常量定义错误码,避免魔术数字。
php
// 抛出业务异常
throw new SaasException(ERROR_Insufficient_BALANCE, '余额不足');

2.5 日志 (Logging)

  • 使用 Facade: 使用 think\facade\Log 进行日志记录。
  • 上下文信息: 日志应包含足够的上下文(User ID, Request ID, 关键参数),便于排查问题。
  • 分级记录:
    • Log::info: 关键业务流程节点(如:任务提交成功、支付回调收到)。
    • Log::error: 异常捕获、系统错误、第三方接口调用失败。
    • Log::debug: 调试信息(生产环境通常关闭)。

✅ 推荐写法:

php
Log::info('[Volcengine] Task Submitted', [
    'user_id' => $userId,
    'task_id' => $taskId,
    'params'  => $params
]);

2.6 安全性 (Security)

  • 输入过滤: 信任 ApiBaseController 和验证器,但仍需注意 SQL 注入(使用绑定参数/ORM)和 XSS(输出转义)。
  • 权限控制: 确保所有敏感接口都进行了 checkLogin 或中间件权限校验。
  • 敏感数据: 密码、密钥等敏感信息严禁明文记录在日志中(需脱敏处理)。

3. 代码规范

  • 遵循 PSR-12: 代码格式遵循 PSR-12 标准。
  • 命名规范:
    • 类名:UpperCamelCase (e.g., VolcengineVisualService)
    • 方法名:lowerCamelCase (e.g., submitTask)
    • 变量名:lowerCamelCase (e.g., userId)
    • 数据库表名/字段:snake_case (e.g., user_id)
  • 注释: 核心逻辑、复杂算法和公共方法必须包含 PHPDoc 注释。

4. 目录结构说明

api/app/
├── base/               # 基础模块 (基类、全局异常、中间件)
├── aigc/               # AIGC 业务模块
│   ├── controller/     # 控制器
│   ├── service/        # 业务逻辑
│   ├── model/          # 数据模型
│   ├── validate/       # 验证器
│   └── route/          # 路由定义
├── ...                 # 其他业务模块
└── extend/             # 扩展类库 (第三方 SDK 封装)

本文档由 Stooland 技术团队维护,修订请联系架构组。