使用 Laravel Eloquent 修改器时要小心点

Laravel

我承认 – 在使用 Laravel 框架工作的五年中, 我沉迷于它的 “magic”, 编写很少的代码就可以实现一个功能. 但是最近, 随着我项目规模的扩大, 这种“magic”开始成为问题. 典型的一个例子是 Eloquent Accessors, 因此在本文中, 我将反对使用他们, 以及说明如何替代它们.


访问器如何工作以及它们为什么很棒

让我们记住, 访问器时如何工作的.想象一下,在 users 数据库表中,您有 name surname 列, 但是您希望展示 full name 。但是你并不想每次将字符串连接在一起, 因此访问器是一个很棒的解决方案!

你只需要在 app/User.php 中定义:

public function getFullNameAttribute()
{
    return $this->name . ' ' . $this->surname;
}

然后, 只要有 $user 对象, 你就可以这样写, 例如, 在 Blade 中:

{{ $user->full_name }}

Eloquent 将负责调用此方法, 还将蛇形属性 full_name 转换为 getFullNameAttribute 驼峰方法. 魔法, 难道不是吗?


问题 1: 此字段是什么?

问题通常发生在大项目和大团队中, 当代码被别人接管时.

例如, 当您的数据表或其它位置有很多字段, 你不能够明确的知道某些字段是访问器. 例如, 如果你看到 $user->full_name 和 $user->home_address , 某些人可能会真的认为它们是数据库里的字段, 对吗?

因此, 访问器影响了代码的可阅读性. 如果一个初级开发者 (或者不熟悉 Laravel 的人) 依据这部分代码进行开发 – 可能需要很长的时间去理解, 为什么这个字段不在数据库中, 并且他们可能花几分钟/几小时来挖掘过去的迁移, 寻找 full_name 列.

此外, 这些字段在 IDE 中是 “不可点击的”, 因此你很难寻找方法内隐藏了什么. 为了查找 “getFullName”, 你需要在你的 IDE (例如 PhpStorm) 中搜索整个项目 (或者模型文件) .


问题 2: 大访问器可能 "隐藏" bug

这里我们有个简单的拼接字符串的例子. 但是我确实经常看到访问器作为成熟的计算方法有超过 20 行的逻辑代码.

想象一下对于国际姓名来说 full_name 可能有更大的逻辑 – 在一些国家中姓名分为 3 个部分, 还有可能包括 “Mr/Mrs/Ms”, 缩写, 大写/小写字母等等. 尽管它仍然有效,但是在这种大逻辑中很可能会出现错误。

而且几乎没有人会为 访问器 编写自动化测试. 如果您看了 code structure point of view, 像这样大的计算逻辑应该写在 Service 层的类中, 这样就可以更方便的进行单元测试.


解决方案: 只需使用“ Getter”方法

那么,如何避免过多的“Magic”呢?简单 – 使用方法就好,而无需任何转换。

因此, 在 Blade 中使用 {{ $user->getFullName() }} 替代 {{ $user->full_name }} 难道不更具有可读性吗?

首先, 可以立刻明白它并不是数据库的一列 – 因为末尾有 () , 很显然这是 方法. 同时, 您的 IDE 将允许点击它, 将方法放入您的模型中. 难道不更容易导航吗?

在模型中,只需将 getFullNameAttribute() 重命名为 getFullName() :

public function getFullName()
{
    return $this->name . ' ' . $this->surname;
}

你同意吗? 您是否曾经在Laravel中遇到过“Magic 过多”的问题 - 使用了访问器或其他魔术方法?

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://laraveldaily.com/the-biggest-pro...

译文地址:https://learnku.com/laravel/t/38986

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 2

api就不能用方法

4年前 评论

@sinofaneliu 倒是也可以使用, 无非就是 自己手动写 .
按照文章所说, 这样:

foreach ($users as $user) {
    $user->full_name = $user->getFullName();
    ......
}

return $users;

但是我觉得这样不太好, 如果用到的地方多, 容易书写出错. 如果字段名 (full_name) 变了 改起来也不方便. 或者 你在Laravel 中使用 Resource , 但是在 lumen 中怎么办? 只能是自己封装一下.

Model User

public function getFullName() {
    this->attributes['full_name'] = $this->name . ' ' . $this->surname;
}

这样就直接调用就可以了.

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!