Laravel 代码开发最佳实践

网友投稿 583 2022-05-30

我们这里要讨论的并不是 Laravel 版的 SOLID 原则(想要了解更多 SOLID 原则细节查看这篇文章)亦或是设计模式,而是 Laravel 实际开发中容易被忽略的最佳实践。

内容概览

单一职责原则

胖模型,瘦控制器

验证

业务逻辑应该放到服务类

DRY(Don't Repeat Yourself,不要重复造轮子)

优先使用 Eloquent 而不是查询构建器和原生 SQL 查询,优先使用集合而不是数组

批量赋值

不要在 Blade 模板中执行查询 & 使用渴求式加载(避免 N+1 问题)

注释代码

不要把 JS 和 CSS 代码放到 Blade 模板里面,不要在 PHP 类中写 HTML 代码

使用配置、语言文件、常量而不是在代码中写死

使用社区接受的标准 Laravel 工具

遵循 Laravel 命名约定

使用更短的、可读性更好的语法

使用 IoC 容器或门面而不是创建新类

不要直接从 .env 文件获取数据

以标准格式存储日期,使用访问器和修改器来编辑日期格式

其他好的实践

单一职责原则

一个类和方法只负责一项职责。

坏代码:

public function getFullNameAttribute()

{

if (auth()->user() && auth()->user()->hasRole('client') && auth()->user()->isVerified()) {

return 'Mr. ' . $this->first_name . ' ' . $this->middle_name . ' ' $this->last_name;

Laravel 代码开发最佳实践

} else {

return $this->first_name[0] . '. ' . $this->last_name;

}

}

好代码:

public function getFullNameAttribute()

{

return $this->isVerifiedClient() ? $this->getFullNameLong() : $this->getFullNameShort();

}

public function isVerfiedClient()

{

return auth()->user() && auth()->user()->hasRole('client') && auth()->user()->isVerified();

}

public function getFullNameLong()

{

return 'Mr. ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name;

}

public function getFullNameShort()

{

return $this->first_name[0] . '. ' . $this->last_name;

}

胖模型、瘦控制器

如果你使用的是查询构建器或原生 SQL 查询的话将所有 DB 相关逻辑都放到 Eloquent 模型或 Repository 类。

坏代码:

public function index()

{

$clients = Client::verified()

->with(['orders' => function ($q) {

$q->where('created_at', '>', Carbon::today()->subWeek());

}])

->get();

return view('index', ['clients' => $clients]);

}

好代码:

public function index()

{

return view('index', ['clients' => $this->client->getWithNewOrders()]);

}

Class Client extends Model

{

public function getWithNewOrders()

{

return $this->verified()

->with(['orders' => function ($q) {

$q->where('created_at', '>', Carbon::today()->subWeek());

}])

->get();

}

}

验证

将验证逻辑从控制器转移到请求类。

坏代码:

public function store(Request $request)

{

$request->validate([

'title' => 'required|unique:posts|max:255',

'body' => 'required',

'publish_at' => 'nullable|date',

]);

....

}

好代码:

public function store(PostRequest $request)

{

....

}

class PostRequest extends Request

{

public function rules()

{

return [

'title' => 'required|unique:posts|max:255',

'body' => 'required',

'publish_at' => 'nullable|date',

];

}

}

业务逻辑需要放到服务类

一个控制器只负责一项职责,所以需要把业务逻辑都转移到服务类中。

坏代码:

public function store(Request $request)

{

if ($request->hasFile('image')) {

$request->file('image')->move(public_path('images') . 'temp');

}

....

}

好代码:

public function store(Request $request)

{

$this->articleService->handleUploadedImage($request->file('image'));

....

}

class ArticleService

{

public function handleUploadedImage($image)

{

if (!is_null($image)) {

$image->move(public_path('images') . 'temp');

}

}

}

DRY

尽可能复用代码,单一职责原则可以帮助你避免重复,此外,尽可能复用 Blade 模板,使用 Eloquent 作用域。

坏代码:

public function getActive()

{

return $this->where('verified', 1)->whereNotNull('deleted_at')->get();

}

public function getArticles()

{

return $this->whereHas('user', function ($q) {

$q->where('verified', 1)->whereNotNull('deleted_at');

})->get();

}

好代码:

public function scopeActive($q)

{

return $q->where('verified', 1)->whereNotNull('deleted_at');

}

public function getActive()

{

return $this->active()->get();

}

public function getArticles()

{

return $this->whereHas('user', function ($q) {

$q->active();

})->get();

}

优先使用 Eloquent 和 集合

通过 Eloquent 可以编写出可读性和可维护性更好的代码,此外,Eloquent 还提供了强大的内置工具如软删除、事件、作用域等。

坏代码:

SELECT *

FROM `articles`

WHERE EXISTS (SELECT *

FROM `users`

WHERE `articles`.`user_id` = `users`.`id`

AND EXISTS (SELECT *

FROM `profiles`

WHERE `profiles`.`user_id` = `users`.`id`)

AND `users`.`deleted_at` IS NULL)

AND `verified` = '1'

AND `active` = '1'

ORDER BY `created_at` DESC

好代码:

Article::has('user.profile')->verified()->latest()->get();

批量赋值

关于批量赋值细节可查看对应文档。

坏代码:

$article = new Article;

$article->title = $request->title;

$article->content = $request->content;

$article->verified = $request->verified;

// Add category to article

$article->category_id = $category->id;

$article->save();

好代码:

$category->article()->create($request->all());

不要在 Blade 执行查询 & 使用渴求式加载

坏代码:

@foreach (User::all() as $user)

{{ $user->profile->name }}

@endforeach

好代码:

$users = User::with('profile')->get();

...

@foreach ($users as $user)

{{ $user->profile->name }}

@endforeach

注释你的代码

坏代码:

if (count((array) $builder->getQuery()->joins) > 0)

好代码:

// Determine if there are any joins.

if (count((array) $builder->getQuery()->joins) > 0)

最佳:

if ($this->hasJoins())

将前端代码和 PHP 代码分离:

不要把 JS 和 CSS 代码写到 Blade 模板里,也不要在 PHP 类中编写 HTML 代码。

坏代码:

let article = `{{ json_encode($article) }}`;

好代码:

或者

上一篇:公文管理用泛微,政务电子化、公文线上办
下一篇:SpringBoot 如何异步编程,老鸟们都这么玩的
相关文章