Hyperf模型关联通过定义返回关联实例的方法实现,需严格遵循方法名、参数顺序及外键约定;一对一用hasOne/belongsTo,一对多用hasMany/belongsTo,多对多用belongsToMany并指定中间表与外键,支持with预加载避免N+1。

Hyperf 模型关联通过在模型类中定义方法实现,本质是返回一个关联关系实例(如 HasOne、BelongsToMany),不需额外注册或注解。关键在于方法名、参数顺序和外键约定要准确,否则预加载或动态属性访问会失败。
一对一(hasOne / belongsTo)
适用于「一个用户对应一个角色」这类场景。注意方向性:
-
正向定义(User → Role):在
User模型中写role()方法,用hasOne() -
反向定义(Role → User):在
Role模型中写user()方法,用belongsTo()
示例(User.php):
public function role()
{
return $this->hasOne(Role::class, 'user_id', 'id');
}说明:
- 第1个参数是关联模型类名;
- 第2个参数是 关联表 的外键字段(roles 表里的 user_id);
- 第3个参数是 本模型 的主键字段(users 表里的 id)。
一对多(hasMany / belongsTo)
适用于「一个用户有多篇文章」。逻辑同上,仅把 hasOne 换成 hasMany:
public function articles()
{
return $this->hasMany(Article::class, 'user_id', 'id');
}调用时返回 Collection 对象,可链式查询:
$user->articles()->where('status', 1)->get();多对多(belongsToMany)
适用于「用户-角色」、「文章-标签」等需中间表的场景。必须显式指定中间表名和两个外键:
public function roles()
{
return $this->belongsToMany(
Role::class,
'role_user', // 中间表名
'user_id', // 当前模型在中间表的外键
'role_id' // 关联模型在中间表的外键
);
}Hyperf 默认会自动处理 pivot 字段(如 pivot_user_id),也可用 withPivot() 显式声明中间表附加字段:
return $this->belongsToMany(...)->withPivot('created_at', 'level');预加载与使用技巧
避免 N+1 查询,用 with() 预加载:
- 单层:
User::query()->with('role')->find(1) - 嵌套:
User::query()->with(['articles', 'role.permissions']) - 带条件:
User::query()->with(['articles' => fn ($q) => $q->where('status', 1)])
获取结果时直接访问动态属性即可:
$user = User::query()->with('role')->find(1);
$roleName = $user->role?->name; // 安全访问,role 可能为 null










