我们即将进入2025年,Laravel仍然是Web开发的首选,提供开发者创建强大高效应用的工具。本文介绍了一些关键的最佳实践、技巧和窍门,无论你使用的是Laravel 9、10还是11,这些指南都能帮助你提升代码质量、简化工作流程,从而交付更好的应用。不论你是初学者还是有经验的开发者,这些见解将帮助你充分利用Laravel,提升开发技能。
保持Laravel更新和保持包的更新
保持Laravel更新有以下几个关键好处:
- 提高安全性:定期发布的重要安全修复保护你的应用。
- 更好的性能:更新通常会提升性能,带来更快的加载时间和更高效的代码。
- 新功能和功能性:保持最新以享受增强开发体验的新功能。
- 兼容性:确保与最新的官方和社区包更好兼容。
保持包的更新:定期运行composer update
至关重要。这种简单的做法是确保包更新到最新功能和安全补丁的最佳方法之一。
如果你害怕更新,可能意味着你的代码测试不充分。
通过采用测试实践,确保重大更新不会破坏你的代码,从而充分利用Laravel的改进。
如果不想用手动更新,那么可以尝试ServBay环境管理工具,像PHP8.4beta版本都已经接入ServBay,通过ServBay可以更方便的保持Laravel及各类包的更新。
通过保持项目良好测试来防止关键错误
自动化测试是一个广泛但常被低估的领域。然而,它是确保项目可靠性的重要最佳实践之一。
维护强大测试套件的关键好处:
- 更少的错误:定期测试有助于及早发现问题,导致更稳定的代码库。
- 更满意的客户:可靠的软件带来满意的用户,他们可以信任你的产品。
- 更满意的雇主:良好测试的项目反映专业精神和对质量的承诺。
- 自信的开发者:有了全面的测试套件,你可以在不担心引入新错误的情况下进行更改。休息后返回项目也变得不再令人生畏。
修改代码时,只需运行php artisan test
识别任何损坏的功能,修复问题并重复此过程!
自动化测试可以显著提高项目的稳定性,从而极大地提升你的职业生涯。
为了帮助你入门,Laracasts提供免费的测试课程。你可以学习PHPUnit(行业标准)和Pest(一种简化PHP测试的现代测试框架)。强烈推荐从Pest From Scratch课程开始。
遵循默认目录组织
你是否考虑过为什么要使用像Laravel这样的框架?
框架提供了结构化的开发方法,确保所有团队成员保持一致并朝着共同目标努力。它们包含丰富的复杂、经过实战测试的功能,让你专注于项目的独特方面,而不被细节困扰。
那么,遵循Laravel的默认项目结构是否被视为最佳实践?当然!原因如下:
- 方便性:Laravel的约定和结构有详细文档。当你在几周或几个月后返回项目时,你会感激默认设置的清晰和熟悉。
- 团队协作:与团队成员一起工作时,每个人都理解Laravel的约定,这使得合作更加容易。利用这种共同知识可以推动项目向前发展,而不是在每个转折点重新发明轮子。
使用自定义表单请求处理复杂验证
Laravel中的自定义表单请求是处理验证的强大工具,提供了几个关键优势:
- 重用验证逻辑:可以轻松重用多个控制器的验证规则,保持代码DRY(Don’t Repeat Yourself)。
- 减少控制器臃肿:通过将验证代码卸载到专用的表单请求类中,保持控制器清晰,专注于处理业务逻辑。
创建自定义表单请求
创建自定义表单请求很简单。只需运行以下Artisan命令:
php artisan make:request StorePostRequest
然后,在控制器中,你可以简单地类型提示请求:
use App\Http\Requests\StorePostRequest;
class PostController
{
public function store(StorePostRequest $request)
{
$validated = $request->validated();
Post::create($validated);
// 其他逻辑...
}
}
增强自定义表单请求
自定义表单请求还可以包含超出验证的附加逻辑。例如,可以通过重写prepareForValidation
方法在数据到达控制器之前规范化输入数据:
public function prepareForValidation()
{
$this->merge([
'slug' => Str::slug($this->title),
]);
}
在此示例中,该方法在验证过程发生之前自动从标题生成slug。
授权管理
自定义表单请求还可以处理授权逻辑。如果你发现使用策略过于繁琐,可以直接在表单请求中包含简单的授权检查。
使用单一动作控制器简化代码库
即使遵循最佳实践,控制器也可能变得笨重。一个很好的解决方案是使用Laravel中的单一动作控制器。这些控制器旨在处理单个动作,而不是像标准资源控制器那样处理多个动作。
创建单一动作控制器
要创建单一动作控制器,使用以下Artisan命令:
php artisan make:controller ShowPostController --invokable
此命令将创建一个仅有一个动作的控制器,命名为__invoke
。有关__invoke
魔术方法的更多信息,请查看Laravel文档。
定义路由
使用单一动作控制器,你可以简化路由定义。以下是如何在路由中使用它:
use App\Http\Controllers\ShowPostController;
// 单一动作控制器路由
Route::get('/posts/{post}', ShowPostController::class);
主观最佳实践
使用单一动作控制器是一种主观的最佳实践。由你和你的团队决定这种方法是否适合项目的结构和可读性偏好。
使用中间件避免代码重复
在Laravel中,中间件是强大的工具,允许你过滤或修改传入请求。通过利用中间件,可以避免代码重复,保持控制器清晰和可管理。以下是一些常见的中间件使用场景:
- 检查所需权限:确保用户有必要的权限访问某些路由。
- 设置用户区域:检查用户的首选语言并相应调整应用程序的区域。
Laravel提供了多种内置中间件,用于常见任务,如身份验证、速率限制等。
创建自定义中间件
要创建自定义中间件,使用以下Artisan命令:
php artisan make:middleware CheckTokens
在你的中间件中,可以定义处理请求的逻辑。以下是检查用户是否有足够令牌的中间件示例:
public function handle(Request $request, Closure $next): Response
{
if (! $request->user()->hasEnoughTokens()) {
abort(403); // 禁止访问
}
return $next($request); // 继续到下一个中间件或请求处理程序
}
将中间件附加到路由
定义中间件后,可以将其附加到任意数量的路由上。这种模块化方法有助于保持代码清晰,并减少控制器中的重复。
Route::middleware('check.tokens')->group(function () {
Route::get('/protected-resource', [ResourceController::class, 'index']);
Route::post('/protected-action', [ResourceController::class, 'store']);
});
使用策略实现授权
在Laravel中,利用策略进行授权对于构建清晰和可维护的应用至关重要。使用策略的三个主要好处:
- 在多个控制器中共享授权逻辑:通过将授权规则整合到策略中,促进一致性并消除应用中的重复代码。
- 减少控制器复杂性:将授权逻辑转移到策略中,使控制器能够专注于其主要任务,从而生成更清晰和更易于理解的代码。
- 简化访问授权代码:将策略放在
app/Policies
目录中,使开发人员在需要时轻松找到和修改授权规则。
来看一个使用策略进行帖子更新的实际场景:
// app/Policies/PostPolicy.php
public function update(User $user, Post $post)
{
return $user->id === $post->user_id; // 验证用户是否拥有该帖子
}
// app/Http/Controllers/PostController.php
public function update(Request $request, Post $post)
{
$this->authorize('update', $post); // 检查更新操作是否被授权
// 如果授权,继续更新过程
// ...
}
确保迁移是最新的
迁移是通过纯PHP代码定义数据库模式的方法。可以将它们视为phpMyAdmin的代码替代方案,提供一种以编程方式管理数据库结构的方法。这种方法对团队特别有益,因为它使每个人都能在本地机器上复制相同的开发环境,并在Git中维护更改的清晰历史记录。
迁移还便于将项目部署到新环境(如暂存或生产)而无需从其他环境导出数据库。然而,常见的陷阱是,有些开发人员直接对数据库进行更改,而不是创建新的迁移。这种做法可能导致其他团队成员的不便,他们可能需要通过Slack请求数据库转储。为了提升项目并保持一致性,重要的是有效利用迁移。
利用匿名迁移防止冲突(Laravel 8及以上)
匿名迁移是避免类名冲突的有效解决方案。使用此功能,你可以创建多个名为“update_posts_table”的迁移而不会遇到错误,这有助于减少开发过程中的摩擦。
在Laravel 9及以上版本中,当你运行以下命令时,会自动生成匿名迁移:
php artisan make:migration UpdatePostsTable
这些迁移的结构如下:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration {
// 迁移逻辑在此处
};
有趣的是,你也可以在Laravel 8中实现匿名迁移。为此,只需将类名替换为return new class
,并确保在末尾包含分号。这样即使在较早版本中也能享受匿名迁移的好处。
正确实现down()方法进行回滚
down()
方法由php artisan migrate:rollback
命令使用,是还原对数据库所做更改的关键。当一些开发人员选择实现它而其他人则不这样做时,重要的是确保如果你使用它,你的down()
方法定义正确。
本质上,down()
方法应反转在up()
方法中执行的操作。以下是一个基本示例:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
return new class extends Migration {
public function up()
{
Schema::table('posts', function (Blueprint $table) {
// 将列从布尔更改为日期时间。
$table->datetime('is_published')->nullable()->change();
});
}
public function down()
{
Schema::table('posts', function (Blueprint $table) {
// 在回滚期间将列恢复到原始状态。
$table->boolean('is_published')->default(false)->change();
});
}
};
如果你不想使用down()
方法,可以简单地将其删除。
遵循Eloquent的数据库表命名指南
遵循Laravel的表命名约定是一个简单的最佳实践,可以极大地造福你的团队。当你使用Artisan命令时,框架会自动处理这些约定,例如php artisan make:model Post --migration --factory
。
如果由于某种原因你无法使用这些命令,这里有一个快速指南:
-
对于名为Post的模型,相应的表应命名为posts,使用复数形式。例如:
-
Comment模型 → comments表
-
Reply模型 → replies表
-
对于连接Post和Comment的中间表(例如comment_post):
-
使用两个名称的单数形式。
-
按字母顺序排列。
有关更多详细信息,请参阅官方文档。
通过使用预加载避免N+1问题
还有更多最佳实践要介绍!你是否遇到过N+1问题?预加载是防止它们的有效方法。
例如,如果你显示30篇帖子及其作者的列表,由于懒加载,Eloquent将为30篇帖子执行一个查询,然后为每个作者执行额外的30个查询(这意味着每次在代码中调用$post->user
时都会检索用户关系)。
解决方案很简单:使用with()
方法将查询数量从31减少到2。
Post::with('author')->get();
为了避免N+1问题,可以配置应用程序在任何关系被懒加载时抛出异常。此限制仅应在本地环境中强制执行。
Model::preventLazyLoading(
// 除非是生产环境,否则返回`true`。
! app()->isProduction()
);
使用Eloquent的严格模式以避免性能问题和错误
Eloquent的严格模式是调试的宝贵工具。它通过在多种情况下抛出异常来帮助开发人员在开发过程中识别潜在问题:
- 懒加载关系:懒加载可能导致性能问题,特别是在处理大型数据集时。这种情况发生在仅在访问时才从数据库中获取相关模型。在严格模式下,如果关系被懒加载,将抛出异常,鼓励使用预加载。
- 分配不可填充属性:Eloquent模型中的
$fillable
属性可防止批量赋值漏洞。如果尝试分配不可填充属性,将触发异常,确保开发人员在处理批量赋值时保持谨慎。 - 访问不存在的属性:尝试访问不存在或未从数据库中检索的属性可能导致不可预测的行为或错误。严格模式将在此类情况下抛出异常,帮助开发人员定位和解决这些问题。
要启用严格模式,将以下代码添加到AppServiceProvider.php
的boot()
方法中:
Model::shouldBeStrict(
// 它只会在生产环境之外启用。
! app()->isProduction()
);
使用更新的方法定义访问器和修改器
Laravel 9引入了一种声明访问器和修改器的新方法。以下是现在应如何实现它们:
use Illuminate\Database\Eloquent\Casts\Attribute;
class Pokemon
{
public function name(): Attribute
{
$locale = app()->getLocale();
return Attribute::make(
get: fn($value) => $value[$locale],
set: fn($value) => [$locale => $value],
);
}
}
此新语法允许你以更简洁的方式定义访问器和修改器。你还可以缓存计算成本高的值:
use Illuminate\Database\Eloquent\Casts\Attribute;
public function someAttribute(): Attribute
{
return Attribute::make(
fn() => /* 执行一些操作。 */
)->shouldCache();
}
相比之下,先前的方法如下所示:
class Pokemon
{
public function getNameAttribute(): string
{
$locale = app()->getLocale();
return $this->attributes['name'][$locale];
}
public function setNameAttribute($value): string
{
$locale = app()->getLocale();
return $this->attributes['name'][$locale] = $value;
}
}
切换到新语法简化了代码并增强了可读性。
使用dispatchAfterResponse()处理长时间运行的任务
在处理耗时任务(例如在提交联系表单后发送电子邮件)时,可以通过延迟任务直到服务器响应用户后改善用户体验。这时dispatchAfterResponse()
派上用场,允许你推迟长时间运行的进程:
SendContactEmail::dispatchAfterResponse($input);
或者,如果你更喜欢使用匿名函数调度任务,可以这样做:
dispatch(function () {
// 在此处执行一些长时间运行的任务。
})->afterResponse();
通过使用dispatchAfterResponse()
,确保用户从服务器接收到更快的响应,而后台任务则不影响用户体验。
使用队列处理长时间运行的任务
在处理计算密集型任务(例如处理用户上传的图像)时,立即执行这些操作可能导致服务器过载和糟糕的用户体验。以下是如何解决:
- 服务器压力:为每个用户提交实时处理任务可能会压垮服务器。
- 用户体验:用户被迫等待,盯着加载屏幕,导致挫败感。
Laravel的队列系统允许你推迟这些长时间运行的任务,按顺序或以受控并行方式运行它们,确保服务器保持响应,用户无需等待。
为了方便管理任务,可以考虑使用Laravel Horizon,它提供了一个用户界面来高效监控和控制队列任务。这样,你可以在后台处理复杂进程的同时保持性能顺畅。
在每次测试前懒惰刷新数据库
在本地环境中进行测试时,最好每次运行测试时使用一个新的数据库。Laravel提供了一种高效的方法来处理这一点,即在你的每次测试前懒惰刷新数据库。这可以通过在测试类中使用RefreshDatabase
特性实现。这样可以确保每次运行测试时,数据库都处于干净状态,消除数据残留带来的潜在问题。
使用 RefreshDatabase
在你的测试类中使用RefreshDatabase
特性:
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase{use RefreshDatabase;
public function test_example(){// 测试逻辑...
}
}
优势
- 一致性:确保每次测试运行时数据库状态一致,避免因状态变化导致的测试失败。
- 隔离:每个测试独立运行,互不干扰,提升测试的可靠性。
安全管理敏感信息
在管理敏感信息时,确保安全性至关重要。以下是一些最佳实践:
使用环境变量
将敏感信息(如API密钥、数据库凭据)存储在.env
文件中,而不是代码库中。
使用Laravel的加密功能
对于需要加密的数据,使用Laravel提供的加密功能:
use Illuminate\Support\Facades\Crypt;
// 加密$encrypted = Crypt::encryptString('敏感信息');
// 解密$decrypted = Crypt::decryptString($encrypted);
定期更新密钥
确保定期更新应用程序密钥(APP_KEY
),并在更新后重新加密数据。
总结
通过遵循这些最佳实践、技巧和窍门,可以显著提高Laravel应用的质量和安全性。这些方法不仅能帮助你编写更高效的代码,还能为用户提供更好的体验。继续学习和应用这些实践,将有助于你在开发中取得更大成功
标签:Laravel,function,控制器,代码,窍门,2025,测试,使用 From: https://blog.csdn.net/2301_79793626/article/details/143329888