0

0

Laravel Eloquent如何使用访问器和修改器_模型属性格式化

尼克

尼克

发布时间:2025-09-30 17:58:02

|

521人浏览过

|

来源于php中文网

原创

访问器和修改器在Eloquent中分别扮演数据格式化与存储处理的角色。访问器(get{Attribute}Attribute)在获取属性时自动格式化数据,如将时间戳转为友好日期、价格分转元;修改器(set{Attribute}Attribute)在保存前处理数据,如密码哈希、字段标准化。它们确保应用层操作便捷安全,同时保持数据库原始性。Laravel 9+推荐使用Attribute::make()统一定义,提升代码可读性。应优先用于属性相关的通用转换逻辑,避免业务层重复处理。需注意性能陷阱:避免在访问器中执行N+1查询,慎用高开销计算;序列化时需通过$appends显式包含虚拟属性;简单类型转换优先使用$casts而非手动编写访问/修改器,以提升性能和维护性。

laravel eloquent如何使用访问器和修改器_模型属性格式化

Laravel Eloquent 中的访问器(Accessors)和修改器(Mutators)是模型层非常强大的特性,它们允许你在从数据库获取数据或向数据库写入数据时,自动对模型属性进行格式化、转换或处理。说白了,它们就是给你的模型属性穿上了一层“外衣”和“内衣”,让你在应用层面操作数据时更方便、更安全,同时保持数据库存储的原始性。

解决方案

要使用访问器和修改器,你需要在你的 Eloquent 模型中定义特定的方法。

访问器 (Accessors)

访问器用于在从模型中检索属性时对其进行格式化。当你尝试访问一个模型属性时,如果存在对应的访问器方法,Eloquent 会自动调用它来处理属性值。

定义一个访问器的方法名格式是 get{AttributeName}Attribute。例如,如果你想格式化 price 属性,你可以定义 getPriceAttribute 方法:

 '¥' . number_format($value / 100, 2), // 假设数据库存储的是分
        );
    }

    // 对于 Laravel 8 及更早版本,或者更简单的场景:
    /*
    public function getPriceAttribute($value)
    {
        return '¥' . number_format($value / 100, 2);
    }
    */

    /**
     * 获取用户全名。
     *
     * @return \Illuminate\Database\Eloquent\Casts\Attribute
     */
    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->first_name . ' ' . $this->last_name,
        );
    }
}

现在,当你访问 Product 模型的 price 属性时,它会自动返回格式化后的字符串:

$product = Product::find(1);
echo $product->price; // 输出: ¥123.45
echo $product->full_name; // 输出: John Doe

修改器 (Mutators)

修改器用于在将属性值保存到数据库之前对其进行修改。当你设置一个模型属性时,如果存在对应的修改器方法,Eloquent 会自动调用它来处理属性值。

定义一个修改器的方法名格式是 set{AttributeName}Attribute。例如,如果你想在保存 password 属性时对其进行哈希处理,你可以定义 setPasswordAttribute 方法:

 Hash::make($value),
        );
    }

    // 对于 Laravel 8 及更早版本,或者更简单的场景:
    /*
    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = Hash::make($value);
    }
    */

    /**
     * 设置产品名称,自动首字母大写。
     *
     * @return \Illuminate\Database\Eloquent\Casts\Attribute
     */
    protected function name(): Attribute
    {
        return Attribute::make(
            set: fn (string $value) => ucfirst($value),
        );
    }
}

当你设置 User 模型的 password 属性时,它会自动被哈希:

$user = new User;
$user->password = 'secret'; // 'secret' 会被哈希后存入数据库
$user->name = 'product a'; // 存入数据库的是 'Product a'
$user->save();

Laravel 9+ 引入了 Illuminate\Database\Eloquent\Casts\Attribute 类,它提供了一种更现代、更统一的方式来定义访问器和修改器,允许你在同一个方法中同时定义 getset 逻辑,代码看起来更整洁。

Eloquent访问器和修改器在数据展示和存储中扮演了什么角色?

我个人觉得,访问器和修改器在数据流转中扮演着“数据守门员”和“数据化妆师”的双重角色。它们的核心价值在于,让你能够在不改变数据库原始存储方式的前提下,灵活地控制数据在应用层面的表现形式和存储逻辑。

数据展示的角度看,访问器就像是数据的“化妆师”。比如,数据库里存的是一个 Unix 时间戳或者 datetime 字符串,但在前端展示时,我们通常需要一个用户友好的格式,像“2023年10月27日 14:30”。如果每次都在视图层或者控制器里手动 format(),那代码会显得冗余且容易出错。有了访问器,你只需要在模型里定义一次 getCreatedAtAttribute,所有用到 created_at 的地方,它就会自动变成你想要的格式。这不仅保证了数据展示的一致性,还大大简化了业务逻辑层和视图层的代码。想象一下,如果一个字段在十个地方都要展示,你只需要改一个访问器方法,而不是十个地方的视图代码,这效率和维护性简直是质的飞跃。

Anyword
Anyword

AI文案写作助手和文本生成器,具有可预测结果的文案 AI

下载

而从数据存储的角度看,修改器则是数据的“守门员”。它在数据进入数据库之前进行拦截和处理。最典型的例子就是密码哈希。用户输入的明文密码,我们绝不能直接存入数据库,必须经过哈希处理。修改器 setPasswordAttribute 就是做这个事的。再比如,用户输入的姓名可能大小写混杂,但你希望数据库里存储的都是首字母大写或者全部小写,修改器就能帮你统一格式。它确保了数据在进入数据库时是符合业务规则和安全要求的,避免了脏数据或者不安全数据的存储。这对于数据的完整性和安全性来说,是至关重要的。在我看来,这种在模型层面封装数据处理逻辑的做法,是符合“单一职责原则”的,让模型真正成为了业务实体的核心。

什么时候应该优先使用Eloquent访问器和修改器,而非直接在业务逻辑层处理?

这是一个我经常思考的问题,尤其是在项目初期规划数据流的时候。我的经验是,当你发现某个属性的格式化或转换逻辑是与该属性本身紧密相关,且在多个地方需要复用时,就应该优先考虑使用 Eloquent 访问器和修改器。

举个例子,如果你有一个 User 模型,它有一个 is_admin 的布尔字段。在数据库里可能存的是 01。但在应用里,你可能希望它直接返回 truefalse,或者返回一个 Admin / Normal User 的字符串。这种“从原始值到表现值”的转换,就是访问器的绝佳场景。如果你在控制器、服务层、甚至多个视图里都写 if ($user->is_admin == 1) { return 'Admin'; } else { return 'Normal User'; },那不仅代码重复,一旦需求变化,比如想改成“管理员”/“普通用户”,你需要改好几个地方。但如果用访问器,你只需要在模型里改一次 getIsAdminAttribute

同样,对于修改器,当某个属性在保存前需要进行一致性、安全性或格式化处理时,它就非常有用。除了前面提到的密码哈希,还有像手机号的格式化(去除空格、连字符),或者将前端传来的 JSON 字符串自动编码成数组存储(虽然 Laravel 的 casts 也能做,但修改器提供更多自定义空间)。这些处理逻辑,如果散落在各个 storeupdate 方法里,会非常分散且难以维护。将它们集中在修改器里,模型自身就具备了“自我净化”和“自我保护”的能力。

当然,这并不是说所有的逻辑都要塞进访问器和修改器。如果某个逻辑是一次性的,或者它涉及到复杂的业务流程和多个模型的协作,那它可能更适合放在服务层、Repository 或者专门的表单请求(Form Request)中。访问器和修改器更像是对单个属性的“微处理”,旨在简化和统一属性的读写行为。过度使用它们来承载复杂的业务逻辑,反而可能让模型变得臃肿,难以理解和测试。我通常会问自己:“这个转换或处理,是不是这个属性的‘本职工作’?”如果是,那它就属于访问器或修改器。

使用访问器和修改器时,有哪些常见的陷阱或性能考量需要注意?

在使用访问器和修改器时,虽然它们极大地提升了开发效率和代码整洁度,但确实也有些“坑”需要注意,尤其是在性能和调试方面。

一个我经常遇到的问题是过度复杂化访问器。有时候,为了方便,我可能会在访问器里不小心引入了额外的数据库查询。比如,一个 getUserRoleNameAttribute 访问器,如果它每次被调用时都去查询 roles 表,那么在一个列表页展示几十个用户时,就可能导致经典的 N+1 查询问题。虽然这不是访问器本身的问题,但它提供了一个隐藏复杂逻辑的“便利通道”。我的建议是,访问器应该尽量保持轻量级,只进行简单的格式化或基于现有属性的计算。如果需要关联查询,应该考虑使用 with() 预加载,或者将该逻辑放在专门的方法或服务中。

另一个需要注意的是序列化行为。当你把一个模型转换成数组 (toArray()) 或 JSON (toJson()) 时,访问器是会被调用的。这意味着,如果你有一个计算量很大的访问器,并且你的 API 接口频繁地返回大量模型数据,这可能会对性能产生一定影响。此外,默认情况下,只有数据库中实际存在的属性才会被序列化。如果你想让访问器创建的“虚拟属性”也包含在序列化结果中,你需要将它们添加到模型的 $appends 属性中:

class User extends Model
{
    protected $appends = ['full_name']; // full_name 是通过访问器生成的
}

这带来一个潜在的陷阱:如果你忘记将一个虚拟属性添加到 $appends,那么在 JSON 响应中它就不会出现,这可能会导致前端同事的困惑。反之,如果你不需要某个访问器属性被序列化,但它又被默认包含,那也可能造成不必要的开销。

调试方面,访问器和修改器有时会增加一点点心智负担。因为你直接访问或设置的属性值,可能并不是实际存储在 $attributes 数组中的原始值。当出现问题时,你需要记住它们的存在,去检查对应的 get...Attributeset...Attribute 方法,而不是直接查看数据库或 $attributes。这在排查一些奇怪的数据格式问题时,确实需要多绕一个弯。

最后,我想说的是,Laravel 的 casts 属性在很多场景下可以作为访问器和修改器的更简洁替代品。比如 datetimebooleanjson 等常见类型,直接在 $casts 数组里定义就行,代码更少,性能也更好,因为它们是 C 语言级别实现的。只有当你需要更复杂的自定义逻辑时,才考虑手写访问器和修改器。在我看来,这是一个很好的“先用简单,再用复杂”的原则体现。

相关专题

更多
laravel组件介绍
laravel组件介绍

laravel 提供了丰富的组件,包括身份验证、模板引擎、缓存、命令行工具、数据库交互、对象关系映射器、事件处理、文件操作、电子邮件发送、队列管理和数据验证。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

319

2024.04.09

laravel中间件介绍
laravel中间件介绍

laravel 中间件分为五种类型:全局、路由、组、终止和自定。想了解更多laravel中间件的相关内容,可以阅读本专题下面的文章。

276

2024.04.09

laravel使用的设计模式有哪些
laravel使用的设计模式有哪些

laravel使用的设计模式有:1、单例模式;2、工厂方法模式;3、建造者模式;4、适配器模式;5、装饰器模式;6、策略模式;7、观察者模式。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

370

2024.04.09

thinkphp和laravel哪个简单
thinkphp和laravel哪个简单

对于初学者来说,laravel 的入门门槛较低,更易上手,原因包括:1. 更简单的安装和配置;2. 丰富的文档和社区支持;3. 简洁易懂的语法和 api;4. 平缓的学习曲线。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

371

2024.04.10

laravel入门教程
laravel入门教程

本专题整合了laravel入门教程,想了解更多详细内容,请阅读专题下面的文章。

81

2025.08.05

laravel实战教程
laravel实战教程

本专题整合了laravel实战教程,阅读专题下面的文章了解更多详细内容。

64

2025.08.05

laravel面试题
laravel面试题

本专题整合了laravel面试题相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.08.05

json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

414

2023.08.07

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

19

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 9万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 9万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

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