laravel 13 推荐用 casts() 方法替代 $casts 数组,自定义 cast 必须实现 castsattributes 并显式处理 null,基础类型需严格匹配数据库字段,且 cast 应保持纯转换、禁止 i/o 或业务逻辑。

Laravel 13 对模型属性类型转换的底层机制没有颠覆性改动,但结合 PHP 8.3+ 新特性与框架自身演进,新增了更安全、更可测、更语义化的使用方式。重点不是“加了什么新 cast 类型”,而是“怎么用得更稳、更清晰、更符合现代 PHP 实践”。
以下是你在 Laravel 13 中应优先采用的几条关键规则和用法:
✅ 用 castUsing() 替代 $casts 数组中写类名字符串
Laravel 9+ 已推荐,Laravel 13 进一步强化其优势:类型安全、IDE 可跳转、单元测试更干净。
protected $casts = [
'price_cents' => MoneyCast::class, // ❌ 旧写法:字符串类名,难调试
];
// ✅ 推荐写法(Laravel 13 最佳实践)
protected function casts(): array
{
return [
'price_cents' => MoneyCast::class,
];
}
// 或更进一步(PHP 8.3+ 支持返回类型推导):
protected function casts(): array
{
return [
'price_cents' => new MoneyCast(),
];
}
⚠️ 注意:
castUsing()是模型方法,必须返回array,键为字段名,值为CastsAttributes实例或类名。它比静态$casts更灵活,支持依赖注入(如需传入货币配置)。
✅ 自定义 Cast 必须实现 CastsAttributes,且 get()/set() 要显式处理 null
Laravel 13 不再容忍“漏掉 null 判断”的 Cast 类——否则序列化、批量赋值或 API 返回时易出错。
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class PhoneNumberCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
if ($value === null) {
return null; // ✅ 必须显式返回 null
}
return new PhoneNumber($value);
}
public function set($model, string $key, $value, array $attributes)
{
if ($value === null) {
return [$key => null]; // ✅ 必须返回 [$key => null]
}
return [$key => $value instanceof PhoneNumber ? $value->toE164() : (string) $value];
}
}
? 提示:
set()方法必须返回关联数组(如[$key => $converted]),不能只赋值给$this->attributes——那是修改器(Mutator)的写法,和 Cast 冲突。
✅ 日期/布尔等基础类型,必须确保数据库字段类型严格匹配
Laravel 13 没放宽校验,反而因 PHP 8.3 的强类型倾向,对不一致更敏感:
-
booleancast → 数据库字段必须是TINYINT(1)(MySQL)或BOOLEAN(PostgreSQL) -
datetime/date→ 字段必须是DATETIME/DATE,不是TIMESTAMP(除非你明确配置了时区对齐) -
json/array→ 字段必须是JSON类型(MySQL 5.7+ / PG);若用TEXT,需手动json_decode,不推荐
验证是否生效?别看 dd($model->active),用:
var_dump(gettype($model->active)); // 看真实类型 var_export($model->active); // 看结构+类型
✅ 避免在 Cast 中做 I/O、查询或复杂逻辑
Laravel 13 强调 Cast 是“纯类型转换层”,不是业务逻辑入口:
- ❌ 不要在
get()里查数据库、调 API、读文件 - ❌ 不要触发事件、发通知、写日志(这些该放 Observer 或 Service)
- ✅ 只做:解析、格式化、对象封装、单位换算(如 cents ↔ dollars)
例如,把 status_code 整数转成枚举?可以:
return Status::from($value) ?? Status::Unknown;
但别在 get() 里查 StatusTranslation::where('code', $value)->first()。
不复杂但容易忽略











