在Laravel项目中,我们常常需要给模型附加数据库里并不存在的数据,或者在读写时自动转换格式。通过动态添加属性和访问器、修改器,可以让模型层承担更多逻辑,减少控制器里的杂乱代码。

一、什么是动态添加属性
动态添加属性是指模型在序列化或使用时,可以包含并非数据表真实字段的值。Laravel中常用两种方式:定义访问器并加入$appends数组,或在运行时用setAttribute方法赋值。
二、传统访问器与修改器写法
在Laravel 9之前,通常使用getXxxAttribute和setXxxAttribute方法。下面示例给用户模型增加一个不存在的full_name属性,并在存密码时自动哈希。
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use IlluminateSupportFacadesHash;
class User extends Model
{
// 动态追加到数组或JSON输出
protected $appends = ['full_name'];
// 访问器:虚拟字段
public function getFullNameAttribute()
{
return $this->first_name . ' ' . $this->last_name;
}
// 修改器:写入前处理
public function setPasswordAttribute($value)
{
$this->attributes['password'] = Hash::make($value);
}
}
三、PHP 8属性风格的访问器
Laravel 9以后支持用PHP 8的#[Computed]和存取器属性,代码更简洁。注意访问器只读时用get,可写时要同时定义set。
<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
use IlluminateSupportFacadesHash;
use IlluminateDatabaseEloquentCastsAttribute;
class User extends Model
{
protected $appends = ['full_name'];
protected function fullName(): Attribute
{
return Attribute::make(
get: fn () => $this->first_name . ' ' . $this->last_name,
);
}
protected function password(): Attribute
{
return Attribute::make(
set: fn ($value) => Hash::make($value),
);
}
}
四、进阶控制技巧
1. 条件追加属性
不是所有接口都要full_name,可在控制器中临时追加:
$user = User::first();
$user->append('full_name');
// 或隐藏
$user->makeHidden('full_name');
2. 避免关系被序列化
使用WithoutRelations让动态属性保留但关系不输出:
$data = $user->withoutRelations()->toArray();
3. 修改器里调用其他属性
修改器可以依赖模型已存在的字段,实现联动转换,比如根据type决定score的换算。
| 场景 | 推荐做法 |
|---|---|
| 只读虚拟字段 | 访问器+appends |
| 写前转换 | 修改器 |
| 接口差异化 | append/makeHidden |
五、小结
动态添加属性配合访问器与修改器,是Laravel模型层非常实用的进阶能力。合理运用可以让数据格式统一、业务逻辑内聚,也方便后期维护。建议新项目直接用属性风格写法,旧项目可逐步迁移。