在 ThinkPHP (TP8)中,模型(Model)的设计非常契合活跃记录模式(Active Record)。模型不仅负责与数据库表进行映射,还封装了丰富的数据操作方法。


以下是基于 TP8 的模型核心用法与最佳实践:


1. 定义与初始化模型

在 TP8 中,模型通常放在 app/model 目录下,采用大驼峰命名,且会自动去除表前缀并对应数据库表。

namespace appmodel;
use thinkModel;

class User extends Model
{
// 如果类名与表名不一致,可手动指定
// protected name = 'user';
// 设置主键(默认为 id)
// protected pk = 'uid';
}


2. 控制器中的实例化方式

在 TP8 中,推荐“按需加载”,直接在控制器方法中调用静态方法或 new 关键字,避免在构造函数中实例化造成不必要的资源消耗。

use appmodelUser;

// 推荐:直接在方法中使用
public function index() {
users = User::select();
return json(users);
}

注:虽然 TP8 支持使用 model('User') 或在 __construct() 中实例化,但官方更推荐按需调用。


3. 核心 CRUD 操作

TP8 的模型支持链式查询和多种数据写入方式:


* 查询数据:

user = User::find(1); // 根据主键查询单条

users = User::where('status', 1)->select(); // 条件查询多条

* 新增数据:支持对象赋值或数组批量写入,使用 allowField() 可防止非法字段注入。

// 方式1:对象赋值

user = new User();

user->name = '李白';

user->save();


// 方式2:数组写入并过滤字段

user = new User();

user->allowField(['name', 'age'])->save([

'name' => '杜甫', 'age' => 19, 'email' => 'test@test.com'

]);

* 更新与删除:

user = User::find(1);

user->name = '李白2';

user->save(); // 更新

User::destroy(1); // 删除(支持软删除)


4. 复杂查询与条件控制

当遇到多条件优先级或重复字段时,TP8 提供了灵活的语法:

* 控制优先级:使用嵌套数组加中括号 ->where() 来包裹需要优先执行的 AND/OR 条件。

* 多条件重复字段 OR 筛选:使用 whereOr([map1, map2]) 可以优雅地处理同一字段不同条件的 OR 查询。


5. 模型关联(Relationships)

TP8 极大地简化了多表关联查询。以“用户”与“用户资料”的一对一关联为例:

// User 模型中定义关联
public function profile() {
return this->hasOne(Profile::class, 'user_id', 'id');
}

// 控制器中查询
user = User::find(19);
return json(user->profile); // 直接以对象属性方式访问关联数据


6. 高级特性:软删除与事件

* 软删除:数据删除时仅标记删除时间,常规查询会自动屏蔽。使用 withTrashed() 可查询包含软删除的数据,使用 restore() 可恢复数据。

* 模型事件:可以在模型中定义 onAfterRead、onBeforeInsert 等静态方法,在数据操作的前后自动触发特定逻辑(如日志记录、数据格式化)。


💡 架构建议

结合 TP8 的特性,建议将密码加密、字段格式转换等与数据强相关的逻辑写在 Model 内部(利用修改器或事件);而将跨模型的业务编排(如:注册成功后同时发送欢迎邮件、初始化积分)放在 Service 层,以保持 Model 的纯粹与轻量。