1. 引言:ThinkORM 3.0 为什么值得重新认识
ThinkORM 是 ThinkPHP 生态中的独立 ORM 组件,可以脱离框架单独使用。到了 3.0 版本,它对 Model 层做了一次彻底重构:不再依赖魔术方法堆砌属性,而是把模型定义建立在 PHP 强类型与 PDO 之上,让 IDE 补全、静态分析和运行时校验都能真正生效。
本文从零开始,带你走一遍 ThinkORM 3.0 的核心用法:强类型模型定义、查询构造器链式操作、数据集对象、参数绑定与断点重连。
下图展示了 ThinkORM 3.0 的整体分层结构,以及本文将要依次介绍的核心模块:
flowchart TD
A[应用代码] --> B[Db门面类与Model模型]
B --> C[查询构造器链式API]
C --> D[参数绑定与PDO预处理]
D --> E[数据库连接断点重连]
E --> F[MySQL等数据库]
C --> G[thinkCollection数据集对象]
G --> A
2. 安装与基础配置
通过 Composer 安装:
composer require topthink/think-orm ^3.0
ThinkORM 3.0 要求 PHP 8.0 及以上版本,并依赖 PDO 扩展。初始化数据库连接:
use think\facade\Db;
Db::setConfig([
'default' => 'mysql',
'connections' => [
'mysql' => [
'type' => 'mysql',
'hostname' => '127.0.0.1',
'database' => 'demo',
'username' => 'root',
'password' => '',
'hostport' => '3306',
'charset' => 'utf8mb4',
// 断点重连,见第 7 节
'break_reconnect' => true,
],
],
]);
3. 强类型模型定义
3.1 属性声明移入构造函数
3.0 最大的变化之一,是模型字段不再散落在类属性上,而是统一在构造函数中声明,并启用 PHP 的属性提升(Constructor Property Promotion)语法。这样字段的类型、默认值、可空性都集中在一处,一目了然。
<?php
namespace app\model;
use think\Model;
class User extends Model
{
protected $name = 'user';
public function __construct(
protected int $id = 0,
protected string $name = '',
protected int $age = 0,
protected string $email = '',
) {
parent::__construct();
}
}
3.2 强类型带来的好处
- IDE 友好:
$user->age能被识别为int,补全与跳转不再靠猜。 - 静态分析可用:PHPStan、Psalm 能对模型字段做类型检查。
- 运行时校验:写入时类型不匹配会尽早暴露,而不是等到数据库报错。
4. 查询构造器链式操作
4.1 Db 门面类
ThinkORM 3.0 通过 Db 门面类提供查询构造器,链式调用风格保持简洁:
use think\facade\Db;
$list = Db::name('user')
->where('age', 14)
->field('id,name,age')
->order('id', 'desc')
->limit(10)
->select();
常用链式方法一览:
| 方法 | 说明 |
|---|---|
where() | 条件筛选,支持数组、闭包、表达式 |
field() | 指定查询字段 |
order() | 排序 |
limit() | 限制条数 |
page() | 分页 |
join() | 关联查询 |
group() | 分组 |
链式调用的执行顺序可以理解为「逐步构建 SQL → 一次性执行 → 返回数据集」,流程如下:
flowchart LR
A[Dbnameuser] --> B[whereage14]
B --> C[fieldidnameage]
C --> D[orderiddesc]
D --> E[limit10]
E --> F[select]
F --> G[生成SQL并参数绑定]
G --> H[PDO预处理执行]
H --> I[返回thinkCollection]
4.2 复杂条件示例
$list = Db::name('user')
->where('age', '>=', 18)
->where(function ($query) {
$query->where('status', 1)
->whereOr('vip', 1);
})
->select();
5. 数据集对象 think\Collection
select() 返回的不是裸数组,而是 think\Collection 数据集对象。它实现了 ArrayAccess、Countable、IteratorAggregate 等接口,因此可以像数组一样使用:
$list = Db::name('user')->select();
// 数组式访问
echo $list[0]['name'];
echo count($list);
// foreach 遍历
foreach ($list as $item) {
echo $item['name'];
}
同时它封装了大量便捷方法,避免手写循环:
// 取出某一列
$names = $list->column('name');
// 过滤
$adults = $list->where('age', '>=', 18);
// 映射
$emails = $list->column('email');
// 转数组
$array = $list->toArray();
这种「数组无差别用法 + 额外封装方法」的设计,让迁移成本极低,又能享受集合操作的便利。
6. 自动参数绑定与预查询
ThinkORM 3.0 的查询构造器默认使用 PDO 预处理语句,所有条件值都会自动参数绑定,而不是拼接进 SQL 字符串:
// 内部生成:SELECT * FROM `user` WHERE `name` = ?
$user = Db::name('user')->where('name', $name)->find();
这意味着即使用户输入包含 ' OR 1=1 -- 这类内容,也只会被当作普通字符串参数处理,从机制上杜绝 SQL 注入。开发者无需手动转义,也不应再使用字符串拼接构造条件。
参数绑定与预查询的防注入机制,可以用下面的流程来理解:
flowchart TD
A[用户输入name] --> B[wherename参数]
B --> C{是否拼接进SQL字符串}
C -->|否| D[生成占位符SQL]
D --> E[PDO预处理prepare]
E --> F[绑定参数execute]
F --> G[输入被当作纯字符串处理]
G --> H[SQL注入失效]
C -->|是| I[存在注入风险]
7. 断点重连:应对数据库抖动
线上环境偶尔会遇到数据库连接被中间件或超时机制断开的情况。ThinkORM 3.0 提供 break_reconnect 配置,开启后当检测到连接失效时会自动重连并重试当前操作:
'connections' => [
'mysql' => [
// ...
'break_reconnect' => true,
],
],
建议在生产环境开启该选项,避免因短暂的数据库抖动导致请求直接失败。需要注意的是,重连只对幂等或可安全重试的查询友好,涉及事务的场景仍需自行控制边界。
8. 小结
ThinkORM 3.0 的核心变化可以概括为三点:
- 模型层强类型化:属性声明移入构造函数,配合属性提升语法,类型清晰、工具友好。
- 查询构造器更安全:链式 API 保持简洁,自动参数绑定从机制上防注入。
- 运行更稳健:
think\Collection提供数组无差别用法,break_reconnect应对连接抖动。
掌握这些基础后,可以进一步探索关联模型、事务与事件等进阶能力。