推荐用自定义 cast 实现模型字段枚举映射,数据库存原始值(int/string),模型属性表现为可读可验证的枚举实例;需定义 backedenum 枚举类并实现 castsattributes 接口的 get/set 方法,支持 null 和非法值兜底处理,最后在模型中通过 $casts 绑定。

Hyperf 3.1 中模型字段映射枚举,推荐用自定义 Cast 实现类型安全的双向转换,而不是直接存取整数或字符串。核心是让数据库只存原始值(如 int 或 string),而模型属性始终表现为可读、可验证的枚举实例。
定义枚举类(支持自动获取描述与校验)
先创建一个标准 PHP 枚举(PHP 8.1+),建议使用 BackedEnum,便于与数据库值对齐:
```php
#[\Hyperf\Constants\Annotation\Constants]
enum UserStatus: int
{
case INACTIVE = 0;
case ACTIVE = 1;
case LOCKED = 2;
public function label(): string
{
return match($this) {
self::INACTIVE => '已停用',
self::ACTIVE => '已启用',
self::LOCKED => '已锁定',
};
}
}
注意:不需要额外安装 hyperf/constants 来支持枚举,PHP 原生 BackedEnum 即可满足 Cast 需求;若需国际化或错误码管理,再叠加 Constants 注解。
编写枚举 Cast 类(实现 CastsAttributes)
新建 App\Casts\UserStatusCast,严格处理 null 和非法值:
```php
namespace App\Casts;
use App\Enums\UserStatus;
use Hyperf\Contract\CastsAttributes;
class UserStatusCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
if ($value === null) {
return null;
}
return UserStatus::from((int)$value) ?? UserStatus::INACTIVE;
}
public function set($model, string $key, $value, array $attributes)
{
if ($value === null) {
return ['status' => null];
}
if ($value instanceof UserStatus) {
return ['status' => $value->value];
}
return ['status' => UserStatus::tryFrom((int)$value)?->value ?? UserStatus::INACTIVE->value];
}
}
关键点:
• get() 返回枚举实例,不是原始值;
• set() 接受枚举实例、整数或 null,统一转为数据库存储值;
• 使用 tryFrom() 避免非法值抛异常,兜底用默认状态。
在模型中声明 cast 并使用
在模型中用 $casts 数组绑定字段和 Cast:
```php
use App\Casts\UserStatusCast;
class User extends Model
{
protected $casts = [
'status' => UserStatusCast::class,
];
}
这样即可自然操作:
```php
// 读取 → 得到枚举实例
$user = User::find(1);
if ($user->status === UserStatus::ACTIVE) {
// …
}
echo $user->status->label(); // “已启用”
// 写入 → 支持多种赋值方式
$user->status = UserStatus::LOCKED;
$user->status = 2;
$user->status = null;
$user->save();
数据库 status 字段保持为 TINYINT 或 SMALLINT,无需改动表结构。
进阶:配合访问器简化 API 输出
若需在 JSON 响应中自动输出标签或代码,可加访问器:
```php
protected $appends = ['status_label'];
protected function getStatusLabelAttribute(): string
{
return $this->status?->label() ?? '';
}
或统一序列化控制(推荐):
```php
protected function casts(): array
{
return [
'status' => UserStatusCast::class,
];
}
public function toArray(): array
{
$data = parent::toArray();
$data['status'] = $this->status?->value;
$data['status_label'] = $this->status?->label();
return $data;
}
这样既保持模型内部强类型,又灵活适配接口需求。











