3 个简单技巧助您立即改进 Laravel 代码
我使用 Laravel 已经有一段时间了,过去几个月我一直专注于改进我的代码和项目结构。所以,为什么不把这些知识分享给 Laravel 的学徒们呢?
让我们一起来看看 Laravel 项目中的几个实际示例,以及如何重构并从中学习。准备好改进你的代码了吗?
1. 重构你的集合,儿子
想象一下,您正在开发一个网站,学生可以在该网站上参与项目并每周进行评分,而您的工作是向他们的导师显示给定项目中所有学生的当前平均分数,有效地评估该项目的平均学生分数,以跟踪进度。
您可能会想出一个这样的项目类:
<?php
class Project extends Model{
/** ... code omitted for brevity **/
public function studentsAverageScore() {
$participants = $this->participants;
$sum = 0;
$totalStudents = 0;
foreach($participants as $participant) {
if ($participant->isStudent()) {
$totalStudents++;
$sum += $participant->student->lastRating()->averageScore();
}
}
return $sum / $totalStudents;
}
}
我们的方法studentsAverageScore()
看起来效果不错。我们循环遍历所有参与者,检查他们是否是学生(例如,有些参与者可能是他们的导师),然后不断计算他们最后评分的平均分(即给定评分中每个标准的平均值)。
这里的问题是,如果有人稍后需要返回此方法修复错误或更改需求,你的队友(甚至你自己)都会foreach
在执行任何操作之前先在脑海中“编译”一下。循环是通用的,就这个例子而言,我们每次循环都会做几件事:检查他们是否是学生,然后将其添加到一个总数中,这个总数只会在 return 语句中再次处理。
当然,这是一个相对简单的例子,但想象一下,如果我们做得更多呢?如果我们想筛选出部分学生,或者为每个学生添加不同的权重,该怎么办?或许可以考虑他们所有的评分,而不仅仅是他们最近的评分?这可能很快就会失控。
那么,我们如何才能更好地表达这些检查和计算呢?更语义化地表达?幸运的是,我们可以使用 Eloquent 提供的一些函数式编程方法。
我们无需手动检查某个参与者是否是学生,而是使用该filter
方法可以只返回学生信息:
<?php
public function studentsAverageScore() {
$participants = $this->participants;
$participants->filter(function ($participant) {
return $participant->isStudent();
});
}
使用filter
函数,我们只需将函数作为参数传递即可,从而仅返回满足条件的参与者。在本例中,此调用将返回$participants
学生的子集。
当然,我们还需要计算他们的平均分数来完成这项工作。现在应该执行 吗foreach
?这仍然不是最优的。average
在我们返回的 Eloquent 集合中,另一个函数中有一个内置的解决方案,方便地称为 。它遵循类似于 的规则filter
,我们只需从整个集合中返回我们想要平均的值即可。最终代码如下所示:
<?php
public function studentsAverageScore() {
$participants = $this->participants;
return $participants->filter(function ($participant) {
return $participant->isStudent();
})->average(function ($participant) {
return $participant->student->lastRating()->averageScore();
});
}
由于平均值返回一个数字,这正是我们想要的。注意我们如何链接调用,以及代码看起来有多好。你几乎可以像阅读自然语言一样阅读它:根据参与者是否是学生进行筛选,然后计算他们最后一次评分的平均分并返回结果。我们的代码意图清晰,代码也更简洁、更语义化。
这不仅适用于 PHP 或 Eloquent,实际上,你也可以用 JavaScript 做类似的事情。这超出了本文的讨论范围,但如果你从未听说过 JavaScript 中的 filter、map 和 reduce,不妨去了解一下。
2. 注意 N+1 查询问题
让我们在技巧 1 的代码上做一些补充。注意我们如何在average
函数中获取给定参与者的学生模型。这非常容易出问题,因为我们通过一次加载多个学生模型,在“后台”执行了额外的 SQL 查询。
更好的解决方案是在第一次查询时立即加载它们。这样做可以大大减少查询次数,而不是进行 N+1 次查询(因此这个可怕的问题得名)。
使用 eloquent 的方法很容易做到with
。让我们重构一下上面的代码:
<?php
public function studentsAverageScore() {
$participants = $this->participants()->with('student')->get();
return $participants->filter(function ($participant) {
return $participant->isStudent();
})->average(function ($participant) {
return $participant->student->lastRating()->averageScore();
});
}
现在,无论何时我们调用$participant->student
,与参与者相关的学生模型在我们第一次调用($this->participants()
)时就已经被缓存了。
(顺便说一句,上面的代码中仍然有一个与此技巧相关的未优化调用 - 你能发现它吗?将其留在评论中)
3. 改进 Blade 文件
我超爱 Blade。它是一款强大的模板引擎,自带于 Laravel,语法也很棒。但你真的充分发挥了它的潜力吗?
我们都必须使用@foreach
来向用户显示一些集合,但是如果集合为空怎么办?一个简单的答案是@if
在 之前使用一个语句@foreach
。事实证明,有一种更好的写法:
<?php
@forelse ($participants as $participant)
<li>{{ $participant->email }}</li>
@empty
<p>No participants in this project :(</p>
@endforelse
@forelse
与 非常相似@foreach
,但添加了@empty
一个部分。比使用 简洁得多@if
,不是吗?
说到@if
,blade 还有另一个我很喜欢的指令:@unless
and @endunless
。它与 完全相反,@if
而且比单纯的带有否定条件的 更好读@if
。如果你用过 Ruby,你就知道它的工作原理。
Laravel 5.5 中新增了一些身份验证的快捷方式:@auth
/@endauth
和@guest
/ @endguest
。它们与直接使用 非常相似@if(Auth::check())
,但可读性更高。以下是 Laravel 5.5 文档中的一个简单示例:
<?php
@auth
// The user is authenticated...
@endauth
@guest
// The user is not authenticated...
@endguest
官方文档中还有更多内容,你也可以编写自己的指令。我强烈推荐它——它能让你模板文件更容易理解,而不是一堆毫无意义的 if。
有更多有用的提示吗?
暂时就这些。如果你有什么好建议,想在项目中用到,欢迎留言!记住:更好的代码意味着更少的时间用于重构和修复 bug。你的团队会感激你的 :)
文章来源:https://dev.to/edmilsonrobson/3-simple-tips-to-improve-your-laravel-code-today-4fdp