Describes PHP and Laravel guidelines provided by Spatie. These rules result in more maintainable, and readable code.
Follow Laravel conventions first. If Laravel has a documented way to do something, use it. Only deviate when you have a clear justification.
?string not string|nullvoid return types when methods return nothingvoid?Type not Type|null/** @return Collection<int, User> */
public function getUsers(): Collection
use \Spatie\Url\Url;
/** @return Url */
/** @var string *//** @var Collection|SomeWeirdVendor\Collection */
/**
* @param array<int, MyObject> $myArray
* @param int $typedArgument
*/
function someFunction(array $myArray, int $typedArgument) {}
/** @return array{
first: SomeClass,
second: SomeClass
} */
if statements that use && into nested if statements for better readability// Happy path last
if (! $user) {
return null;
}
if (! $user->isActive()) {
return null;
}
// Process active user...
// Short ternary
$name = $isFoo ? 'foo' : 'bar';
// Multi-line ternary
$result = $object instanceof Model ?
$object->name :
'A default value';
// Ternary instead of else
$condition
? $this->doSomething()
: $this->doSomethingElse();
// Bad: compound condition with &&
if ($user->isActive() && $user->hasPermission('edit')) {
$user->edit();
}
// Good: nested ifs
if ($user->isActive()) {
if ($user->hasPermission('edit')) {
$user->edit();
}
}
/open-source)->name('openSource')){userId})[Controller::class, 'method']PostsController)index, create, store, show, edit, update, destroy)pdf-generator.php)chrome_path)config/services.php, don't create new filesconfig() helper, avoid env() outside config filesdelete-old-records)$this->comment('All ok!'))$items->each(function(Item $item) {
$this->info("Processing item id `{$item->id}`...");
$this->processItem($item);
});
$this->comment("Processed {$items->count()} items.");
Be very critical about adding comments as they often become outdated and can mislead over time. Code should be self-documenting through descriptive variable and function names.
Adding comments should never be the first tactic to make code readable.
Instead of this:
// Get the failed checks for this site
$checks = $site->checks()->where('status', 'failed')->get();
Do this:
$failedChecks = $site->checks()->where('status', 'failed')->get();
Guidelines:
{} bracketspublic function rules() {
return [
'email' => ['required', 'email'],
];
}
Validator::extend('organisation_type', function ($attribute, $value) {
return OrganisationType::isValid($value);
});
@if($condition)
Something
@endif
Gate::define('editPost', ...)view instead of show__() function over @lang:/errors/error-occurrences/error-occurrences/1
/errors/1/occurrences
UserController, OrderStatus)getUserName, $firstName)/open-source, /user-profile)pdf-generator.php)chrome_path)php artisan delete-old-records)Controller (PostsController)openSource.blade.php)CreateUser, SendEmailNotification)UserRegistering, UserRegistered)Listener suffix (SendInvitationMailListener)Command suffix (PublishScheduledPostsCommand)Mail suffix (AccountActivatedMail)Resource/Transformer (UsersResource)OrderStatus, BookingType)else statements when possibleif conditions using && into nested if statementsuse statements — never use inline fully qualified class names (e.g. \Exception, \Illuminate\Support\Facades\Http)$exception not $e, $request not $r)