PHP coding standards that apply across all Laravel projects.
final by default
void return type when
method returns nothing
// ✅ Preferred - short nullable notation
public function getName(): ?string
{
return $this->name;
}
// ✅ Preferred - void return type
public function logMessage(string $message): void
{
Log::info($message);
}
// ✅ Avoid final by default - allows for testing and extension
class UserService
{
public function processUser(User $user): void
{
// Implementation that can be overridden if needed
}
}
// ❌ Avoid - unnecessarily restrictive
final class UserService
{
// This prevents mocking in tests and extension
}
// ❌ Avoid - verbose nullable notation
public function getName(): string|null
{
return $this->name;
} // ✅ Preferred - typed properties
class User extends Model
{
protected string $name;
protected ?string $email;
protected Carbon $created_at;
protected Collection $orders;
}
// ✅ No docblock needed - types are clear
public function createUser(string $name, string $email): User
{
return User::create([
'name' => $name,
'email' => $email,
]);
}
// ✅ Meaningful docblock when context is needed
/**
* Calculate the user's subscription renewal date based on their current plan.
*
* Takes into account plan-specific billing cycles and grace periods.
*/
public function calculateRenewalDate(User $user): Carbon
{
return $user->subscription->end_date->addMonth();
}
// ❌ Avoid - redundant docblock
/**
* Create a new user.
*
* @param string $name The user's name
* @param string $email The user's email
* @return User The created user
*/
public function createUser(string $name, string $email): User
{
return User::create(['name' => $name, 'email' => $email]);
}
// ❌ Avoid - untyped properties
class User extends Model
{
protected $name; // What type is this?
protected $email; // Is this nullable?
} use for each trait
else if statements
// ✅ Preferred - early return pattern
public function processUser(User $user): void
{
if (! $user->isActive()) {
return;
}
if (! $user->hasPermission('process')) {
return;
}
$this->processUserData($user);
}
// ✅ Preferred - string interpolation
$message = "Hello {$user->name}, your order #{$order->id} is ready!";
// ✅ Preferred - PascalCase enum values
enum OrderStatus: string
{
case Pending = 'Pending';
case Processing = 'Processing';
case Completed = 'Completed';
}
// ✅ Preferred - traits on separate lines
class UserController extends Controller
{
use AuthorizesRequests;
use ValidatesRequests;
use DispatchesJobs;
}
// ✅ Preferred - separate compound conditions
public function canAccessResource(User $user, Resource $resource): bool
{
if (! $user->isActive()) {
return false;
}
if (! $user->hasRole('admin')) {
return false;
}
if ($resource->isRestricted()) {
return false;
}
return true;
}
// ❌ Avoid - nested conditionals and concatenation
public function processUser(User $user): void
{
if ($user->isActive()) {
if ($user->hasPermission('process')) {
$this->processUserData($user);
} else {
Log::info('User ' . $user->name . ' lacks permission');
}
} else {
Log::info('User ' . $user->name . ' is inactive');
}
} // ✅ Preferred - expressive code eliminates need for comments
public function sendWelcomeEmailToNewUser(User $user): void
{
if ($this->userHasOptedOutOfEmails($user)) {
return;
}
$this->emailService->sendWelcomeEmail($user);
}
// ✅ Good comment - explains business logic
public function calculateShippingCost(Order $order): int
{
$baseCost = 500; // Cents - minimum shipping cost set by logistics team
// Free shipping promotion for orders over $50 (5000 cents)
if ($order->total >= 5000) {
return 0;
}
return $baseCost + $this->calculateDistanceCost($order);
}
// ❌ Avoid - comments explaining obvious code
public function createUser(array $data): User
{
// Create a new user with the provided data
$user = new User();
// Set the user's name
$user->name = $data['name'];
// Set the user's email
$user->email = $data['email'];
// Save the user to the database
$user->save();
// Return the created user
return $user;
}
// ✅ Better - no comments needed
public function createUser(array $data): User
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
]);
}