Trong bài viết này mình sẽ chia sẻ các quy ước viết code trong Laravel & PHP nhé.
General PHP Rules
Code style phải theo chuẩn PSR-1, PSR-2 and PSR-12 . Nói chung mọi thứ như là strings cái không được public-facing(hiển thị công khai) thì nên sử dụng quy tắc đặt tên camelCase.
Void return types
Nếu một phương thức không trả về cái gì, nó nên được trả về kiểu void. Điều này làm cho người khác đọc code của bạn hiểu hơn về code của bạn viết.
Typed properties
Bạn nên định nghĩa loại thuộc tính bất cứ khi nào có thể. Không sử dụng một docblock.
// goodclassFoo{publicstring$bar;}// badclassFoo{/** @var string */public$bar;}
Docblocks
Không sử dụng docblocks cho methods cái bạn có thể thêm type hinted đầy đủ( trừ khi bạn cần mô tả).
Chỉ thêm một mô tả khi nó cung cấp nhiều ngữ cảnh.Sử dụng các câu đầy đủ để mô tả, bao gồm cả dấu chấm ở cuối.
// GoodclassUrl{publicstaticfunctionfromString(string$url):Url{// ...}}// Bad: The description is redundant, and the method is fully type-hinted.classUrl{/**
* Create a url from a string.
*
* @param string $url
*
* @return SpatieUrlUrl
*/publicstaticfunctionfromString(string$url):Url{// ...}}
Luôn sử dụng tên lớp đầy đủ trong docblock.
// Good
/**
* @param string $url
*
* @return SpatieUrlUrl
*/
// Bad
/**
* @param string $foo
*
* @return Url
*/
Docblocks cho các biến lớp là bắt buộc, vì hiện tại không có cách nào khác để gõ các biến này.
// Good
class Foo
{
/** @var SpatieUrlUrl */
private $url;
/** @var string */
private $name;
}
// Bad
class Foo
{
private $url;
private $name;
}
Khi có thể, docblock nên được viết trên một dòng.
// Good
/** @var string */
/** @test */
// Bad
/**
* @test
*/
Nếu một biến có nhiều kiểu, thì kiểu xuất hiện phổ biến nhất là kiểu đầu tiên.
// Good
/** @var SpatieGooBar|null */
// Bad
/** @var null|SpatieGooBar */
Strings
// Good
$greeting = "Hi, I am {$name}.";
// Bad
$greeting = 'Hi, I am ' . $name . '.';
Ternary operators
Mỗi phần của một biểu thức bậc ba phải nằm trên một dòng riêng trừ khi đó là một biểu thức thực sự ngắn.
// Good$result=$objectinstanceofModel?$object->name:'A default value';$name=$isFoo?'foo':'bar';// Bad$result=$objectinstanceofModel?$object->name:'A default value';
If statements
Bracket position
Luôn sử dụng dấu ngoặc nhọn.
// Goodif($condition){...}// Badif($condition)...
Happy path
Nói chung, một hàm nên có phần unhappy path ở trước và phần happy path ở sau cùng. Trong hầu hết các trường hợp, điều này sẽ làm cho phần happy path nằm trong một phần không được chú ý của hàm khiến nó dễ đọc hơn.
// Goodif(!$goodCondition){thrownewException;}// do work
// Badif($goodCondition){// do work}thrownewException;
Avoid else
Tránh sử dụng else bởi vì nó làm code khó đọc hơn. Trong hầu hết các trường hợp, nó có thể được cấu trúc lại bằng cách sử dụng trả về sớm. Điều này cũng sẽ khiến phần happy path ở cuối cuối cùng, điều đáng mong đợi.
// Goodif(!$conditionBA){// conditionB A failedreturn;}if(!$conditionB){// conditionB A passed, B failedreturn;}// condition A and B passed
// Badif($conditionA){if($conditionB){// condition A and B passed}else{// conditionB A passed, B failed}}else{// conditionB A failed}
Compound ifs
Nói chung, các câu lệnh if riêng biệt nên được ưu tiên hơn một điều kiện ghép. Điều này làm cho việc gỡ lỗi code dễ dàng hơn.
// Goodif(!$conditionA){return;}if(!$conditionB){return;}if(!$conditionC){return;}// do stuff
// badif($conditionA&&$conditionB&&$conditionC){// do stuff}
Comments
Nên tránh tối đa nhận xét bằng cách viết mã biểu cảm. Nếu bạn cần sử dụng nhận xét, hãy định dạng nó như sau:
// There should be a space before a single line comment.
/*
* If you need to explain a lot you can use a comment block. Notice the
* single * on the first line. Comment blocks don't need to be three
* lines long or three characters shorter than the previous line.
*/
Whitespace
Các câu lệnh phải có hơi thở. Nói chung, luôn luôn thêm các dòng trống giữa các câu lệnh, trừ khi chúng là một chuỗi các thao tác tương đương với một dòng.
// GoodpublicfunctiongetPage($url){$page=$this->pages()->where('slug',$url)->first();if(!$page){returnnull;}if($page['private']&&!Auth::check()){returnnull;}return$page;}// Bad: Everything's cramped together.publicfunctiongetPage($url){$page=$this->pages()->where('slug',$url)->first();if(!$page){returnnull;}if($page['private']&&!Auth::check()){returnnull;}return$page;}
// Good: A sequence of single-line equivalent operations.publicfunctionup(){Schema::create('users',function(Blueprint$table){$table->increments('id');$table->string('name');$table->string('email')->unique();$table->string('password');$table->rememberToken();$table->timestamps();});}
Không thêm bất kỳ dòng trống nào giữa các dấu ngoặc vuông {}.
// Goodif($foo){$this->foo=$foo;}// Badif($foo){$this->foo=$foo;}
Configuration
Các tệp cấu hình phải sử dụng quy tắc đặt tên kebab-case(dấu gạch ngang).
config/
pdf-generator.php
Các key cấu hình phải sử dụng quy tắc đặt tên snake_case(dấu gạch dưới).
// config/pdf-generator.phpreturn['chrome_path'=>env('CHROME_PATH'),];
Tránh sử dụng trình trợ giúp env bên ngoài tệp cấu hình. Hãy tạo giá trị cấu hình từ biến env như trên.
Artisan commands
Tất cả các tên được đặt cho các lệnh thủ công đều phải được đặt bằng kebab-cased.
# Good
php artisan delete-old-records
# Bad
php artisan deleteOldRecords
Routing
Các url hiển thị công khai(Public-facing urls) phải sử dụng quy tắc đặt tên kebab-case.
https://spatie.be/open-source
https://spatie.be/jobs/front-end-developer
Route names phải sử dụng camelCase.
Route::get('open-source','[email protected]')->name('openSource');
<a href="{{ route('openSource') }}">
Open Source
</a>
Tất cả các routes đều có một http verb(get, post, put, delete), đó là lý do tại sao chúng tôi thích đặt verb này đầu tiên khi xác định một route. Nó làm cho một nhóm các routes rất dễ đọc. Bất kỳ tùy chọn route nào khác nên đi sau nó.
// good: all http verbs come firstRoute::get('/','[email protected]')->name('home');Route::get('open-source','[email protected]')->name('openSource');// bad: http verbs not easily scannableRoute::name('home')->get('/','[email protected]');Route::name('openSource')->get('[email protected]');
Route parameters nên sử dụng quy tắc camelCase.
Route::get('news/{newsItem}','[email protected]');
route url không được bắt đầu bằng / trừ khi url là một chuỗi trống.
// goodRoute::get('/','[email protected]');Route::get('open-source','[email protected]');//badRoute::get('','[email protected]');Route::get('/open-source','[email protected]');
Controllers
Controllers phải đặt tên theo số nhiều.
classPostsController{// ...}
Cố gắng giữ cho bộ điều khiển đơn giản và bám vào các từ khóa CRUD mặc định(index, create, store, show, edit, update, destroy).
Trong ví dụ sau, chúng ta có [email protected] và [email protected], hoặc chúng ta có thể giải nén nó vào một FavoritePostsController riêng biệt.
classPostsController{publicfunctioncreate(){// ...}// ...publicfunctionfavorite(Post$post){request()->user()->favorites()->attach($post);returnresponse(null,200);}publicfunctionunfavorite(Post$post){request()->user()->favorites()->detach($post);returnresponse(null,200);}}
Ở đây chúng ta quay trở lại các từ CRUD mặc định, store và destroy.
classFavoritePostsController{publicfunctionstore(Post$post){request()->user()->favorites()->attach($post);returnresponse(null,200);}publicfunctiondestroy(Post$post){request()->user()->favorites()->detach($post);returnresponse(null,200);}}
Views
View files phải sử dụng camelCase.
resources/
views/
openSource.blade.php
classOpenSourceController{publicfunctionindex(){returnview('openSource');}}
Validation
Khi sử dụng nhiều quy tắc cho một trường trong một yêu cầu biểu mẫu, hãy tránh sử dụng |, luôn sử dụng ký hiệu mảng. Sử dụng ký hiệu mảng sẽ giúp áp dụng các lớp quy tắc tùy chỉnh cho một trường dễ dàng hơn.
// goodpublicfunctionrules(){return['email'=>['required','email'],];}// badpublicfunctionrules(){return['email'=>'required|email',];}
Tất cả các quy tắc xác thực tùy chỉnh phải sử dụng snake_case:
Validator::extend('organisation_type',function($attribute,$value){returnOrganisationType::isValid($value);});
Blade Templates
Thụt lề bằng cách sử dụng bốn dấu cách.
<a href="/open-source">
Open Source
</a>
Không thêm dấu cách sau cấu trúc điều khiển.
@if($condition)
Something
@endif
Authorization
Các chính sách phải sử dụng camelCase.
Gate::define('editPost',function($user,$post){return$user->id==$post->user_id;});
@can('editPost', $post)
<a href="{{ route('posts.edit', $post) }}">
Edit
</a>
@endcan
Translations
Translations phải được hiển thị bằng hàm __ . Chúng tôi thích sử dụng cái này hơn @lang trong Blade vì __ có thể được sử dụng trong cả các chế độ xem Blade và mã PHP thông thường. Dưới đây là một ví dụ:
<h2>{{ __('newsletter.form.title') }}</h2>
{!! __('newsletter.form.description') !!}
Tham khảo: https://github.com/spatie/guidelines.spatie.be/blob/master/content/code-style/laravel-php.md
Nguồn: viblo.asia