ThinkPHP接口开发中模型是数据操作统一出口,需严格遵循PSR-4规范命名与路径、显式定义表名/主键/隐藏字段/类型转换,并用with预载关联避免N+1,禁用$connection动态切库。

UserModel::get(1) 或 UserModel::where('status', 1)->select() 就能直接返回结构化数据,无需额外封装。
模型文件位置和命名必须严格匹配表名与 PSR-4 规范
模型类名决定它默认找哪张表:User 类对应 user 表(带前缀则为 tp_user),UserProfile 对应 tp_user_profile。路径必须是 app/model/User.php,命名空间必须为 app\model。
- 错误写法:
app/model/user.php(小写文件名)或App\Model\User(大写命名空间)→ 自动加载失败 - 表名含大写字母(如
userLog)?必须显式指定:protected $table = 'user_log'; - 主键不是
id?加protected $pk = 'uid';,否则get($id)查不到
protected $table 和 $tableName 的区别别搞混
$table 是完整表名(含前缀),$tableName 是不带前缀的表名,框架优先用 $table;若两者都设,$table 生效。
- 想让
User模型查members表(无前缀):用protected $table = 'members'; - 想让
User查tp_users表(有前缀但类名不匹配):用protected $tableName = 'users';,前缀仍走database.php配置 - 动态切换库?别碰
$connection属性,接口高频场景下容易引发连接复用混乱,改用Db::connect($config)->name('user')->select()更稳妥
API 场景下模型字段要主动控制,别依赖 select *
接口返回全字段不仅慢,还可能暴露敏感字段(如 password、is_deleted)。模型里加 protected $hidden = ['password', 'salt']; 或 protected $visible = ['id', 'name', 'email']; 最直接。
-
$hidden和$visible互斥,只用一个;同时设会以$visible为准 - 时间字段自动转格式?加
protected $type = ['create_time' => 'datetime:Y-m-d H:i:s']; - 需要 JSON 返回时字段驼峰?模型里不处理,交给控制器:
json($user->toArray(), 200, [], ['convert_keys' => true])
关联模型在 API 中怎么用才不拖慢响应
一对多查用户订单,写 $user->orders 看似简洁,但默认是懒加载——第一次访问才查,控制器里多次调用会 N+1 查询。接口必须预载。
立即学习“PHP免费学习笔记(深入)”;
- 查单个用户及其订单:
UserModel::with('orders')->find($id) - 查多个用户并预载头像:
UserModel::with(['avatar' => function ($q) { $q->field('id, url'); }])->select() - 关联定义在模型里必须明确:
public function orders() { return $this->hasMany(Order::class, 'user_id'); },漏掉第二个参数(外键)就会查错表
app/model/ 下那个 PHP 文件没按规则写清楚。



















