Code style
Basic code standards and naming conventions that helps our code to be clean and neat.
General rules
- Code style must follow PSR-1, PSR-2 and PSR-12.
- If a method return nothing, it should be indicated with void.
- Don’t use docblocks for methods that can be fully type hinted (unless we need a description)
- We should type a property whenever possible. Avoid using a docblock. (PHP 7.4+)
// good
class Foo
{
public string $bar;
}
// bad
class Foo
{
/** @var string */
public $bar;
}
Ternary operators
// Good
$result = $object instanceof Model
? $object->name
: 'A default value';
$name = $isFoo ? 'foo' : 'bar';
// Bad
$result = $object instanceof Model ?
$object->name :
'A default value';
If statements
// Good
if ($condition) {
...
}
// Bad
if ($condition) ...
Strings
Prefer string interpolation above sprintf and the . operator.
// Good
$greeting = "Hi, I am {$name}.";
// Bad
$greeting = 'Hi, I am ' . $name . '.';
Early return
To keep readability in functions and methods, it is wise to return early if simple conditions apply that can be checked at the beginning of a method:
// Good
if (!$foo) {
return null;
}
// do work
return $work;
// Bad
if ($foo) {
// do work
} else {
return null;
}
Comments
// 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.
*/
// $this->foo = $bar; There should be a space before single line code comment.
Whitespace
In general, we should always add blank lines between statements, unless they’re a sequence of single-line equivalent operations. This isn’t something enforceable, it’s a matter of what looks best in its context.
public function getPage($url)
{
$page = $this->pages()->where('slug', $url)->first();
if (!$page) {
return null;
}
if ($page['private'] && ! Auth::check()) {
return null;
}
return $page;
}
Configuration
Configuration files must use kebab-case.
config/
pdf-generator.php
Configuration keys must use snake_case.
// config/pdf-generator.php
return [
'chrome_path' => env('CHROME_PATH'),
];
We should avoid using the env helper outside of configuration files. Create a configuration value from the env variable like above.
Routes
Public-facing urls must use kebab-case.
http://code.imagdic.me/docs/code-style/
http://code.imagdic.me/docs/code-style/kebab-case/my-own-documentation
Route names must use camelCase.
Route::get('open-source', 'OpenSourceController@index')->name('openSource');
<a href="{{ route('openSource') }}">
Open Source
</a>
All routes have an http verb, that’s why we like to put the verb first when defining a route. It makes a group of routes very readable. Any other route options should come after it.
// good: all http verbs come first
Route::get('/', 'HomeController@index')->name('home');
Route::get('open-source', 'OpenSourceController@index')->middleware('openSource');
// bad: http verbs not easily scannable
Route::name('home')->get('/', 'HomeController@index');
Route::middleware('openSource')->get('OpenSourceController@index');
Route parameters should use camelCase.
Route::get('news/{newsItem}', 'NewsItemController@index');
A route url should not start with / unless the url would be an empty string.
// good
Route::get('/', 'HomeController@index');
Route::get('open-source', 'OpenSourceController@index');
//bad
Route::get('', 'HomeController@index');
Route::get('/open-source', 'OpenSourceController@index');
A route url must always be in plural.
// good
Route::get('movies', 'MovieController@index');
Route::get('movies/{movie}', 'MovieController@show');
//bad
Route::get('opportunity', 'OpportunityController@index');
Route::get('opportunities/{id}', 'OpportunityController@show');
Route::get('people', 'PeopleController@index');
Route::get('person/{id}', 'PeopleController@show');
We should define controllers as tuple in routes.
Route::get('routes/{route}', [App\Http\Controllers\RouteController::class, 'show']);
Read more about this at freek.dev
Controllers
Controllers that control a resource must use the singular resource name.
class PostController
{
// ...
}
Try to keep controllers simple and stick to the default CRUD keywords (index, create, store, show, edit, update, destroy). Extract a new controller if you need other actions.
In the following example, we could have PostController@favorite, and PostController@unfavorite, or we could extract it to a separate FavoritePostController.
class PostController
{
public function create()
{
// ...
}
// ...
public function favorite(Post $post)
{
request()->user()->favorites()->attach($post);
return response(null, 200);
}
public function unfavorite(Post $post)
{
request()->user()->favorites()->detach($post);
return response(null, 200);
}
}
Here we fall back to default CRUD words, store and destroy.
class FavoritePostController
{
public function store(Post $post)
{
request()->user()->favorites()->attach($post);
return response(null, 200);
}
public function destroy(Post $post)
{
request()->user()->favorites()->detach($post);
return response(null, 200);
}
}
This is a loose guideline that doesn’t need to be enforced.
Views
View files must use kebab-case.
resources/views/open-source.blade.php
class OpenSourceController
{
public function index() {
return view('open-source');
}
}
Validation
When using multiple rules for one field in a form request, avoid using |, always use array notation. Using an array notation will make it easier to apply custom rule classes to a field.
// good
public function rules()
{
return [
'email' => ['required', 'email'],
];
}
// bad
public function rules()
{
return [
'email' => 'required|email',
];
}