Sign In Create Account
General PHP Rules

General PHP Rules

PHP coding standards that apply across all Laravel projects.

Class Defaults

  • • Avoid using final by default
  • • Prefer short nullable type notation
  • • Use void return type when method returns nothing

Class Defaults Examples

// ✅ 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;
}

Typed Properties & Docblocks

  • • Type properties whenever possible
  • • Minimize docblocks - avoid for fully type-hinted methods
  • • Only add descriptions that provide meaningful context
  • • Use full sentences with proper punctuation in docblocks
  • • Import class names
  • • Keep docblocks concise

Typed Properties & Docblocks Examples

// ✅ 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?
}

Code Style

  • • Use PascalCase for enum values
  • • List each trait on its own line
  • • Use use for each trait
  • • Prefer string interpolation
  • • Put multi-line ternary expressions on separate lines
  • • Always use curly brackets for if statements
  • • Prefer early returns over else
  • • Separate compound conditions into individual if statements

Code Style Examples

// ✅ 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');
  }
}

Comments

  • • Avoid comments by writing expressive code
  • • Add space before single-line comments
  • • Consider creating descriptive functions instead of comments
  • • Use comments to explain "why", not "what"

Comments Examples

// ✅ 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'],
  ]);
}