Laravel模型Casts通过$casts属性自动转换数据库与PHP类型,解决数据类型不一致、减少重复代码、提升可读性与安全性,支持内置类型如boolean、array、datetime及自定义Casts处理复杂场景如Value Object。

Laravel模型Casts是一种相当精妙的机制,它允许我们在模型属性从数据库读取出来,或者在存入数据库之前,自动进行类型转换。简单来说,它就是给你的模型属性套上了一层“翻译器”,确保你拿到的数据是你期望的类型,并且在存回去时也能正确地适配数据库字段。这极大地简化了数据处理的逻辑,让代码更干净、更易读。
Laravel模型Casts的核心在于模型类中的
$casts
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'is_published' => 'boolean', // 数据库可能是tinyint(1),这里直接转成true/false
'options' => 'array', // 数据库存的是JSON字符串,这里直接转成PHP数组
'published_at' => 'datetime', // 数据库是datetime/timestamp,这里转成Carbon日期对象
'price' => 'float', // 确保价格字段始终是浮点数
'settings' => 'json', // 也可以用'json',行为与'array'类似,但更明确
];
// ...
}当你从数据库中获取一个
Post
$post = Post::find(1);
$post->is_published
$post->options
$post->published_at
说实话,刚开始接触Laravel的时候,我可能没有立刻意识到Casts的重要性。但随着项目复杂度的增加,尤其是在处理一些非标准数据类型时,Casts的价值就凸显出来了。最直接的痛点就是数据类型不一致。
想想看,数据库里存日期通常是
DATETIME
TIMESTAMP
DATETIME
Carbon
new Carbon($post->published_at)
$post->published_at->format('Y-m-d H:i:s')Carbon
另一个常见场景是JSON数据。很多时候,我们会在数据库的一个文本字段里存储配置信息、用户偏好等JSON字符串。手动
json_decode()
json_encode()
array
json
此外,布尔值的表示也是个小麻烦。数据库的
TINYINT(1)
0
1
true
false
boolean
总结来说,Casts解决了以下几个核心痛点:
Laravel内置的Casts类型已经相当丰富了,几乎覆盖了我们日常开发中会遇到的所有基础数据类型转换。了解它们,并知道何时使用,是高效开发的关键。
这里列举一些常用的内置Casts类型:
string
integer
real
float
double
float
double
real
decimal:<digits>
'price' => 'decimal:2'
123.456
123.46
boolean
0
1
false
true
object
stdClass
array
json
array
collection
Illuminate\Support\Collection
date
Carbon
DATETIME
Carbon
TIMESTAMP
Carbon
immutable_date
immutable_datetime
immutable_timestamp
ImmutableDateTime
如何选择合适的Casts?
我的经验是,首先看数据库字段的实际存储类型和你的业务需求。
INT
integer
decimal:X
TINYINT(1)
boolean
array
collection
json
collection
date
DATETIME
TIMESTAMP
immutable_
一个小建议是,尽量让Casts的类型与你的业务逻辑中最常使用的类型保持一致。比如,如果你经常需要对一个JSON字段进行链式操作,
collection
array
date
DATETIME
有时候,内置的Casts类型无法满足我们的复杂需求,比如处理一个自定义的Value Object,或者在存取数据时进行一些特殊的加密/解密操作。这时候,自定义Casts就派上用场了。它提供了一个强大的扩展点,让你可以完全控制属性的序列化和反序列化过程。
实现自定义Casts需要创建一个类,并实现
Illuminate\Contracts\Database\Eloquent\CastsAttributes
get($model, $key, $value, $attributes)
$value
set($model, $key, $value, $attributes)
$value
让我们看一个简单的例子,假设我们有一个
Money
1. 定义Money
// app/ValueObjects/Money.php
<?php
namespace App\ValueObjects;
class Money
{
protected int $cents; // 以分为单位存储
public function __construct(float $amount)
{
$this->cents = (int) round($amount * 100);
}
public function toDollars(): float
{
return $this->cents / 100;
}
public function __toString(): string
{
return (string) $this->toDollars();
}
}2. 创建自定义Cast类:
// app/Casts/MoneyCast.php
<?php
namespace App\Casts;
use App\ValueObjects\Money;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use InvalidArgumentException;
class MoneyCast implements CastsAttributes
{
/**
* Cast the given value.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value // 从数据库读取的原始值 (可能是整数或字符串)
* @param array $attributes
* @return \App\ValueObjects\Money
*/
public function get($model, $key, $value, $attributes)
{
if (is_null($value)) {
return null;
}
// 数据库存储的是以分为单位的整数
return new Money($value / 100);
}
/**
* Prepare the given value for storage.
*
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $key
* @param mixed $value // PHP中设置的值 (可能是Money对象或浮点数)
* @param array $attributes
* @return mixed // 返回数据库可存储的类型 (整数)
*/
public function set($model, $key, $value, $attributes)
{
if (is_null($value)) {
return null;
}
if ($value instanceof Money) {
return (int) round($value->toDollars() * 100);
}
if (is_numeric($value)) {
return (int) round($value * 100);
}
throw new InvalidArgumentException('The given value is not a Money instance or a numeric value.');
}
}3. 在模型中使用自定义Cast:
// app/Models/Product.php
<?php
namespace App\Models;
use App\Casts\MoneyCast;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $casts = [
'price' => MoneyCast::class, // 假设数据库中 price 字段存储的是以分为单位的整数
];
// ...
}现在,当你获取
$product->price
Money
$product->price = new Money(19.99);
$product->price = 25.50;
何时应该考虑自定义Casts?
自定义Casts是一个非常强大的工具,但也不是万能药。我认为以下几种情况是考虑自定义Casts的良好时机:
Money
Address
总之,自定义Casts的引入,通常是为了让你的模型属性在PHP层面更符合领域模型,更易于理解和操作,同时将底层的数据库存储细节隔离开来。这有助于提升代码的内聚性和可维护性。
以上就是Laravel模型Casts?Casts如何使用定义?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号