โ†“Skip to main content
Understanding Object-Oriented Design in PHP
  1. Blog Posts/

๐Ÿ—๏ธ Writing Better Laravel Code with SOLID Principles

3 min readยท
solid php laravel

Published on: 2022-10-17

Laravel remains one of the most popular PHP frameworks today, and writing maintainable code is critical as your project scales.

One of the core foundations of good software design is the SOLID principles. Letโ€™s explore how these principles apply to a Laravel project, with examples and a class diagram to tie it together.


โš™๏ธ Prerequisites

  • Laravel version: 9.x (current LTS release)
  • PHP version: 8.0+

๐Ÿงฉ What is SOLID?

  • S: Single Responsibility Principle
  • O: Open/Closed Principle
  • L: Liskov Substitution Principle
  • I: Interface Segregation Principle
  • D: Dependency Inversion Principle

๐Ÿ” Example Context: User Registration Flow

Imagine youโ€™re building a user registration feature with email verification. Hereโ€™s a bad design:

class UserController extends Controller
{
  public function register(Request $request)
  {
    $validated = $request->validate([...]);
    $user = User::create($validated);

    // Sending email directly here violates SRP
    Mail::to($user->email)->send(new WelcomeMail($user));

    return response()->json($user);
  }
}

๐Ÿšจ Why is this bad?

The controller:

  • Handles validation
  • Creates the user
  • Sends email

It violates the Single Responsibility Principle by doing too much.


โœ… Applying SOLID Principles

1. Single Responsibility Principle (SRP)

Each class or method should have only one reason to change. Refactor:

class UserService
{
  public function register(array $data): User
  {
    $user = User::create($data);
    event(new UserRegistered($user));
    return $user;
  }
}

Now your UserController only handles the HTTP layer, and the email logic moves to an event listener.


2. Open/Closed Principle (OCP)

Your code should be open for extension, closed for modification.

Instead of modifying UserService to handle SMS welcome messages in the future, extend functionality via events and listeners:

// EventServiceProvider.php
protected $listen = [
  UserRegistered::class => [
    SendWelcomeEmail::class,
    SendWelcomeSMS::class,
  ],
];

3. Liskov Substitution Principle (LSP)

Child classes must be substitutable for parent classes. Example:

If you extend Laravelโ€™s Notification class, your subclass should work anywhere a Notification is expected without breaking functionality.


4. Interface Segregation Principle (ISP)

Donโ€™t force classes to implement interfaces they donโ€™t use. Example:

Instead of a single bloated interface:

interface UserActions {
  public function login();
  public function register();
  public function logout();
  public function verifyEmail();
}

Split into smaller, focused interfaces.


5. Dependency Inversion Principle (DIP)

High-level modules should not depend on low-level modules. Both should depend on abstractions.

For example, using repositories:

interface UserRepositoryInterface {
  public function create(array $data): User;
}

class EloquentUserRepository implements UserRepositoryInterface {
  public function create(array $data): User {
    return User::create($data);
  }
}

Inject UserRepositoryInterface instead of a concrete implementation in your service.


๐Ÿ“Š SOLID Principle Class Diagram (Laravel Context)


๐Ÿง  TL;DR

  • Laravel 9 + PHP 8 support clean OOP patterns out of the box.
  • Following SOLID principles improves readability, testability, and extensibility.
  • Use events, services, and interfaces to keep your Laravel codebase robust.