首页 > php框架 > Laravel > 正文

Laravel模型Casts?Casts如何使用定义?

小老鼠
发布: 2025-09-05 09:05:02
原创
318人浏览过
Laravel模型Casts通过$casts属性自动转换数据库与PHP类型,解决数据类型不一致、减少重复代码、提升可读性与安全性,支持内置类型如boolean、array、datetime及自定义Casts处理复杂场景如Value Object。

laravel模型casts?casts如何使用定义?

Laravel模型Casts是一种相当精妙的机制,它允许我们在模型属性从数据库读取出来,或者在存入数据库之前,自动进行类型转换。简单来说,它就是给你的模型属性套上了一层“翻译器”,确保你拿到的数据是你期望的类型,并且在存回去时也能正确地适配数据库字段。这极大地简化了数据处理的逻辑,让代码更干净、更易读。

Laravel模型Casts的核心在于模型类中的

$casts
登录后复制
属性。它是一个关联数组,键是模型属性名,值是你希望转换成的类型。比如,如果你有一个数据库字段存储的是JSON字符串,但你希望在PHP代码中直接操作数组或对象,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
登录后复制
会是一个PHP数组,而
$post->published_at
登录后复制
则是一个Carbon日期对象。当你修改这些属性并保存时,Laravel也会自动将它们转换回数据库所需的格式(例如,布尔值转为0或1,数组转为JSON字符串)。这种自动化处理,在我看来,是Laravel在开发者体验上做得非常出色的一点。

为什么我们需要Laravel模型Casts?它解决了哪些常见痛点?

说实话,刚开始接触Laravel的时候,我可能没有立刻意识到Casts的重要性。但随着项目复杂度的增加,尤其是在处理一些非标准数据类型时,Casts的价值就凸显出来了。最直接的痛点就是数据类型不一致

想想看,数据库里存日期通常是

DATETIME
登录后复制
TIMESTAMP
登录后复制
,PHP里我们习惯用
DATETIME
登录后复制
对象或者Laravel的
Carbon
登录后复制
。没有Casts,每次从数据库取出来,你都得手动
new Carbon($post->published_at)
登录后复制
,或者在保存前
$post->published_at->format('Y-m-d H:i:s')
登录后复制
。这不仅麻烦,还容易出错,而且代码里会充斥着大量的类型转换逻辑,变得非常臃肿。Casts直接帮你抹平了这种差异,你只管操作
Carbon
登录后复制
对象就行。

另一个常见场景是JSON数据。很多时候,我们会在数据库的一个文本字段里存储配置信息、用户偏好等JSON字符串。手动

json_decode()
登录后复制
json_encode()
登录后复制
的循环简直是噩梦。Casts的
array
登录后复制
json
登录后复制
类型直接让你可以像操作普通PHP数组一样操作这些数据,极大地提升了开发效率和代码的可读性。

此外,布尔值的表示也是个小麻烦。数据库的

TINYINT(1)
登录后复制
字段,取出来可能是
0
登录后复制
1
登录后复制
的字符串或整数。在PHP逻辑中,我们更喜欢直接用
true
登录后复制
false
登录后复制
。Casts的
boolean
登录后复制
类型完美解决了这个问题。

总结来说,Casts解决了以下几个核心痛点:

  • 减少重复代码: 避免了手动进行大量的类型转换。
  • 提高代码可读性 模型属性的类型在代码层面更明确,一目了然。
  • 降低出错率: 自动化处理减少了人为转换的错误。
  • 简化复杂数据类型处理: 比如日期、JSON、集合等,让它们在PHP中更自然地被使用。

Laravel内置了哪些Casts类型?我们该如何选择合适的Casts?

Laravel内置的Casts类型已经相当丰富了,几乎覆盖了我们日常开发中会遇到的所有基础数据类型转换。了解它们,并知道何时使用,是高效开发的关键。

这里列举一些常用的内置Casts类型:

  • string
    登录后复制
    : 确保属性是字符串。
  • integer
    登录后复制
    ,
    real
    登录后复制
    ,
    float
    登录后复制
    ,
    double
    登录后复制
    : 确保属性是对应的数值类型。
    float
    登录后复制
    double
    登录后复制
    在PHP中基本等价,
    real
    登录后复制
    是它们的别名。
  • decimal:<digits>
    登录后复制
    : 将字符串转换为浮点数,并指定小数点后的位数。例如
    'price' => 'decimal:2'
    登录后复制
    会将
    123.456
    登录后复制
    转换为
    123.46
    登录后复制
    。这在处理货数据时非常有用。
  • boolean
    登录后复制
    : 将数据库的
    0
    登录后复制
    /
    1
    登录后复制
    false
    登录后复制
    /
    true
    登录后复制
    转换为PHP的布尔值。
  • object
    登录后复制
    : 将JSON字符串转换为PHP的
    stdClass
    登录后复制
    对象。
  • array
    登录后复制
    : 将JSON字符串转换为PHP数组。
  • json
    登录后复制
    : 行为与
    array
    登录后复制
    类似,但更明确地表示存储的是JSON。
  • collection
    登录后复制
    : 将JSON字符串转换为
    Illuminate\Support\Collection
    登录后复制
    实例。这个非常强大,可以直接使用集合的所有方法。
  • date
    登录后复制
    : 将数据库日期字符串转换为
    Carbon
    登录后复制
    日期对象,通常只包含日期部分(年-月-日)。
  • DATETIME
    登录后复制
    : 将数据库日期时间字符串转换为
    Carbon
    登录后复制
    日期对象,包含日期和时间。
  • TIMESTAMP
    登录后复制
    : 将Unix时间戳(整数)转换为
    Carbon
    登录后复制
    日期对象。
  • immutable_date
    登录后复制
    ,
    immutable_datetime
    登录后复制
    ,
    immutable_timestamp
    登录后复制
    : 与上述对应,但返回的是
    ImmutableDateTime
    登录后复制
    对象,这意味着对日期对象的修改会返回新实例,而不是修改原实例。这在某些场景下可以避免意外的副作用。

如何选择合适的Casts?

我的经验是,首先看数据库字段的实际存储类型和你的业务需求

落笔AI
落笔AI

AI写作,AI写网文、AI写长篇小说、短篇小说

落笔AI 41
查看详情 落笔AI
  • 数字类型: 如果数据库是
    INT
    登录后复制
    ,用
    integer
    登录后复制
    ;如果需要精确到小数点后几位,
    decimal:X
    登录后复制
    是首选,避免浮点数精度问题。
  • 布尔值: 数据库是
    TINYINT(1)
    登录后复制
    ,毫无疑问用
    boolean
    登录后复制
  • JSON数据: 如果你只是需要一个简单的PHP数组,用
    array
    登录后复制
    。如果你想更明确地表达这是JSON数据,或者希望利用
    collection
    登录后复制
    的强大功能,
    json
    登录后复制
    collection
    登录后复制
    会更合适。
  • 日期时间: 这是最常见的。如果数据库只存日期,用
    date
    登录后复制
    ;如果包含时间,用
    DATETIME
    登录后复制
    。如果数据库存的是Unix时间戳,用
    TIMESTAMP
    登录后复制
    。如果你特别在意日期对象的不可变性,
    immutable_
    登录后复制
    系列是你的朋友。

一个小建议是,尽量让Casts的类型与你的业务逻辑中最常使用的类型保持一致。比如,如果你经常需要对一个JSON字段进行链式操作,

collection
登录后复制
会比
array
登录后复制
更方便。如果一个日期字段你几乎只用来显示,而很少进行日期计算,那么
date
登录后复制
DATETIME
登录后复制
就足够了。

如何实现自定义Casts?何时应该考虑自定义Casts?

有时候,内置的Casts类型无法满足我们的复杂需求,比如处理一个自定义的Value Object,或者在存取数据时进行一些特殊的加密/解密操作。这时候,自定义Casts就派上用场了。它提供了一个强大的扩展点,让你可以完全控制属性的序列化和反序列化过程。

实现自定义Casts需要创建一个类,并实现

Illuminate\Contracts\Database\Eloquent\CastsAttributes
登录后复制
接口。这个接口要求你实现两个方法:

  1. get($model, $key, $value, $attributes)
    登录后复制
    : 当属性从数据库中读取出来时,这个方法会被调用。你可以在这里将原始的数据库值
    $value
    登录后复制
    转换成你想要的PHP类型。
  2. set($model, $key, $value, $attributes)
    登录后复制
    : 当属性被赋值并准备保存到数据库时,这个方法会被调用。你在这里将PHP类型的值
    $value
    登录后复制
    转换回数据库可以存储的原始类型。

让我们看一个简单的例子,假设我们有一个

Money
登录后复制
Value Object,它内部以分为单位存储金额,但在应用中我们希望以元为单位操作。

1. 定义

Money
登录后复制
Value Object (可选,但通常自定义Casts会配合Value Object使用):

// 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的良好时机:

  • Value Objects: 当你的领域模型中存在Value Objects(例如
    Money
    登录后复制
    Address
    登录后复制
    Email
    登录后复制
    等),并且你希望它们在模型属性中被自然地使用时。
  • 复杂的数据结构: 如果数据库字段存储的是一些需要特殊解析或序列化的复杂数据(例如,一个加密的字符串,一个需要特定格式化的地理坐标),自定义Casts可以帮你封装这些逻辑。
  • 第三方API数据格式化 如果你的应用需要与外部API交互,并且API的数据格式与数据库或PHP模型不完全匹配,自定义Casts可以在存取时进行适配。
  • 数据清洗/转换: 在某些情况下,你可能需要在数据从数据库出来时进行一些轻量级的数据清洗或格式转换,自定义Casts提供了一个集中的地方来处理这些。

总之,自定义Casts的引入,通常是为了让你的模型属性在PHP层面更符合领域模型,更易于理解和操作,同时将底层的数据库存储细节隔离开来。这有助于提升代码的内聚性和可维护性。

以上就是Laravel模型Casts?Casts如何使用定义?的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号