ThinkPHP8 多应用项目开发规范与目录结构最佳实践

编程记录 · 9 天前

在现代 Web 开发中,项目的可维护性、可扩展性和团队协作效率是至关重要的。ThinkPHP8 提供了强大的多应用支持,通过合理的目录结构和开发规范,可以显著提升项目的整体质量。本文将详细介绍一个“能直接落地”的 ThinkPHP8 多应用目录结构模板,并逐层说明控制器、模型、服务层等各层的职责、命名规范和开发流程,帮助团队一次性对齐开发规范。

一、项目目录结构模板

以下是一个典型的 ThinkPHP8 多应用项目目录结构,以新建两个应用 indexadmin 为例:

├─ app                      // 应用总目录
│  ├─ index                 // 【前台】应用
│  │  ├─ controller         // 控制器层:只负责「接收请求、调度、返回」
│  │  │  ├─ Index.php       // 默认首页控制器(类名:Index,文件名Index.php)
│  │  │  ├─ user            // 多级控制器(URL:/user/profile)
│  │  │  │  └─ Profile.php  // 类名:User\Profile(注意命名空间)
│  │  ├─ model              // 数据层:一张表一个文件,只做「最原子」的 CURD
│  │  │  ├─ User.php        // 类名:app\index\model\User,对应表前缀+user表
│  │  │  └─ Order.php
│  │  ├─ logic              // 逻辑层(可选):拼装复杂查询、事务、业务规则
│  │  │  └─ UserLogic.php   // 类名:app\index\logic\UserLogic
│  │  ├─ service            // 服务层(可选):跨应用/跨模块可复用的“纯业务”
│  │  │  └─ PayService.php  // 类名:app\index\service\PayService
│  │  ├─ validate           // 验证器:一一对应控制器方法
│  │  │  └─ UserValidate.php
│  │  ├─ middleware         // 应用级中间件
│  │  ├─ event.php          // 事件监听定义
│  │  ├─ route              // 应用路由,仅对本应用生效
│  │  │  └─ app.php
│  │  └─ view               // 视图(若前后端不分离)
│  │     └─ index\index.html
│  │
│  ├─ admin                 // 【后台】应用,目录层级与 index 完全一致
│  │  ├─ controller
│  │  ├─ model
│  │  ├─ logic
│  │  ├─ service
│  │  ├─ validate
│  │  ├─ middleware
│  │  ├─ route
│  │  └─ view
│  │
│  └─ common                // 多应用共享代码
│     ├─ model              // 公共模型(如AdminBase、CommonLogic)
│     ├─ service            // 全局服务(SmsService、FileService…)
│     ├─ middleware         // 全局中间件(Auth、Log、Cors…)
│     ├─ bootstrap.php      // 应用启动时统一加载
│     └─ event.php          // 全局事件
│
├─ config                   // 全局配置
│  ├─ app.php               // 开启 auto_multi_app => true
│  ├─ database.php
│  └─ …
├─ public                   // Web 根
│  ├─ index.php             // 单入口
│  └─ static                // 静态资源
├─ runtime                  // 缓存、日志、文件缓存
└─ extend / vendor          // 本地扩展 & Composer 包

二、各层职责与命名规范

  1. 控制器(controller)

职责:只负责接收请求、调用业务逻辑、渲染视图或返回 JSON 数据。禁止出现 SQL 或业务规则。

命名规范:

  • 类名与文件名一致,采用驼峰命名法。例如:Index.php → 类名 Index
  • 多级控制器再加一层子目录,例如 user/Profile.php → 类名 User\Profile
  • 强制使用 validateValidate 类完成入参校验,控制器里不出现 $_POST 直接取值。

示例:

namespace app\index\controller;

use app\index\logic\UserLogic;
use think\facade\Request;
use think\facade\View;

class Index
{
    public function index()
    {
        $data = Request::param();
        $result = UserLogic::getUserInfo($data);
        return View::fetch('index/index', ['data' => $result]);
    }
}
  1. 模型(model)

职责:一张主表对应一个 Model 文件,只封装“最原子”的 CURD、自动时间戳、软删、关联模型。所有对表字段的默认值、枚举转换、获取器/修改器,写在 Model;不出现复杂联表。

命名规范:

  • 表名转驼峰,例如 user_cardsUserCards.php
  • 类名与文件名一致,采用驼峰命名法。

示例:

namespace app\index\model;

use think\Model;

class User extends Model
{
    protected $name = 'user'; // 数据表名
    protected $autoWriteTimestamp = true; // 自动时间戳
    protected $deleteTime = 'delete_time'; // 软删除字段

    public function orders()
    {
        return $this->hasMany(Order::class);
    }
}
  1. 逻辑层(logic)

职责:当“一个业务需要操作多张表 or 需要事务 or 需要缓存/加锁”时,在 Logic 里拼装。一个 Logic 类通常对应一个“业务域”,如 OrderLogic::createOrder()

命名规范:

  • 类名与文件名一致,采用驼峰命名法。例如:UserLogic.php → 类名 UserLogic

示例:

namespace app\index\logic;

use app\index\model\User;
use think\Exception;

class UserLogic
{
    public static function getUserInfo($data)
    {
        try {
            $user = User::where('id', $data['id'])->find();
            if (!$user) {
                throw new Exception('User not found');
            }
            return $user->toArray();
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
    }
}
  1. 服务层(service)

职责:与具体应用无关、可跨应用/跨项目复用的“纯业务”才下沉到 Service,如 SmsServiceFileService。Service 里禁止直接 use think\facade\Db,只能调用 Model/Logic 提供的接口,保持可单元测试。

命名规范:

  • 类名与文件名一致,采用驼峰命名法。例如:PayService.php → 类名 PayService

示例:

namespace app\index\service;

use app\index\logic\UserLogic;

class PayService
{
    public function processPayment($data)
    {
        $userInfo = UserLogic::getUserInfo($data);
        // 处理支付逻辑
        return true;
    }
}
  1. 公共层(common)

职责:多应用都要用的代码统一放在 app/common;若以后拆微服务,可直接把 common 打成 Composer 包。common 里也可以再细分 model/service/middleware 子目录,命名空间统一 app\common\xxx

示例:

namespace app\common\model;

use think\Model;

class CommonModel extends Model
{
    // 公共模型方法
}

三、快速生成命令(TP8 内置)

ThinkPHP8 提供了强大的命令行工具,可以快速生成应用骨架和多层文件,提高开发效率。

# 生成应用骨架
php think build demo

# 生成多层文件
php think make:controller demo@user/Member   # 多级控制器
php think make:model demo@User               # 模型
php think make:logic demo@UserLogic          # 需安装 topthink/think-logic 或手写
php think make:validate demo@UserValidate    # 验证器

四、开发流程小结

  1. 需求评审:明确需求,确定功能模块。
  2. 建表:根据需求设计数据库表结构。
  3. 先写 Model:封装表结构、字段、关联、获取器等。
  4. 再写 Logic/Service:实现业务逻辑,确保代码复用性和可测试性。
  5. 最后写 Controller:接收参数、调用业务逻辑、返回响应。控制器代码保持简洁,通常不超过 10 行。

遵循“控制器永远‘薄’,模型永远‘原子’,业务永远‘下沉’,跨应用代码永远进 common”的原则,可以确保项目的长期可维护性、可扩展性和团队协作效率。

五、总结

通过合理的目录结构和开发规范,ThinkPHP8 多应用项目可以实现高效开发、易于维护和扩展。希望本文介绍的目录结构模板和开发规范能够帮助团队快速对齐,提升项目的整体质量。

Theme Jasmine by Kent Liao