DEV Community

Cover image for Laravel 12 + PHP 8.4 Clean Code: Real-World Refactoring Examples Every Developer Should Know
Moolchand Sharma
Moolchand Sharma

Posted on • Originally published at Medium

Laravel 12 + PHP 8.4 Clean Code: Real-World Refactoring Examples Every Developer Should Know

Clean Code in Laravel 12: Stop Writing Ugly PHP and Start Using These Real-Life Fixes

Your code works — but does it spark joy?

Laravel 12 and PHP 8.4 give us so many tools to write elegant, expressive code. Yet most devs still write spaghetti Laravel controllers, bulky foreach blocks, and forget about value objects or modern PHP features.

Let’s fix that.

In this guide, I’ll show messy vs. clean code side by side using Laravel 12 + PHP 8.4. These are things every Laravel dev has done — and how to do them better.


🧱 Example 1: Validating and Creating a Model in Controller

😵 Messy Code

public function store(Request $request)
{
    $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
        'password' => 'required|string|min:8',
    ]);
    $user = new User();
    $user->name = $request->name;
    $user->email = $request->email;
    $user->password = Hash::make($request->password);
    $user->save();
    return response()->json($user);
}
Enter fullscreen mode Exit fullscreen mode

✅ Clean Code (Laravel 12 + Form Request + Constructor Promotion)

// app/Http/Requests/StoreUserRequest.php
class StoreUserRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => 'required|string|min:8',
        ];
    }

    public function authorize(): bool
    {
        return true;
    }
}
Enter fullscreen mode Exit fullscreen mode
// app/Services/UserService.php
class UserService
{
    public function __construct(
        protected User $user
    ) {}

  public function create(array $data): User
    {
        return $this->user->create([
            ...Arr::except($data, 'password'),
            'password' => Hash::make($data['password']),
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode
// Controller
public function store(StoreUserRequest $request, UserService $service)
{
    return response()->json(
        $service->create($request->validated())
    );
}
Enter fullscreen mode Exit fullscreen mode

🧱 Example 2: Filtering with if/foreach Soup

😵 Messy Code

$activeUsers = [];

foreach ($users as $user) {
    if ($user->is_active) {
        $activeUsers[] = $user;
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ Clean Code (Using Collection Pipeline)

$activeUsers = collect($users)->filter->is_active;
Enter fullscreen mode Exit fullscreen mode

Or if you’re working with Eloquent:

$activeUsers = User::where('is_active', true)->get();
Enter fullscreen mode Exit fullscreen mode

Laravel collections + Eloquent FTW.


🧱 Example 3: Boolean Checks in Views

😵 Messy Blade

@if($user->is_admin)
    <span class="badge bg-success">Admin</span>
@else
    <span class="badge bg-secondary">User</span>
@endif
Enter fullscreen mode Exit fullscreen mode

✅ Clean Blade with Component or Enum

Use PHP 8.1+ enums for roles:

enum Role: string {
    case Admin = 'admin';
    case User = 'user';
}
Enter fullscreen mode Exit fullscreen mode

And in Blade:

<x-badge :type="$user->role === Role::Admin ? 'success' : 'secondary'">
    {{ $user->role->name }}
</x-badge>
Enter fullscreen mode Exit fullscreen mode

🧱 Example 4: Date Formatting Repeated Everywhere

😵 Messy Code

{{ \Carbon\Carbon::parse($user->created_at)->format('d M, Y') }}
Enter fullscreen mode Exit fullscreen mode

✅ Clean Code with Accessor

// In User.php model
protected function createdAt(): Attribute
{
    return Attribute::make(
        get: fn($value) => \Carbon\Carbon::parse($value)->format('d M, Y'),
    );
}
Enter fullscreen mode Exit fullscreen mode

Now in Blade:

{{ $user->created_at }}
Enter fullscreen mode Exit fullscreen mode

Beautifully clean.


🧱 Example 5: Deep Nested Conditionals

😵 Messy Code

if ($user) {
    if ($user->is_active) {
        if (!$user->is_banned) {
            // do something
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ Clean Code with Early Returns

if (!$user || !$user->is_active || $user->is_banned) {
    return;
}

// do something
Enter fullscreen mode Exit fullscreen mode

Even better:

if ($user?->is_active && !$user->is_banned) {
    // do something
}
Enter fullscreen mode Exit fullscreen mode

Laravel 12 + PHP 8.4 makes this easier with nullsafe and match expressions.


⚡ Bonus Tips: Laravel 12 + PHP 8.4 Goodies

✅ Read-only classes for DTOs:

readonly class CreateUserData {
    public function __construct(
        public string $name,
        public string $email,
        public string $password
    ) {}
}
Enter fullscreen mode Exit fullscreen mode

✅ Match expressions over switch:

return match($status) {
    'active' => 'Active',
    'inactive' => 'Inactive',
    'banned' => 'Banned',
};
Enter fullscreen mode Exit fullscreen mode

✅ Invokable Actions:

class SendWelcomeEmail {
    public function __invoke(User $user) { ... }
}

app(SendWelcomeEmail::class)($user);
Enter fullscreen mode Exit fullscreen mode

✅ Higher-order pipelines:

$users = User::query()
    ->when($isAdmin, fn($q) => $q->where('role', 'admin'))
    ->get();
Enter fullscreen mode Exit fullscreen mode

🧠 Final Thoughts

Just because your code works, doesn’t mean it’s good.

Clean code in Laravel 12 + PHP 8.4 is:

  • ✨ Expressive
  • 🧪 Testable
  • 🧼 Maintainable
  • 🚀 Scalable

If you liked this, share it or drop a comment!

Want a part 2 with clean test cases or API resource patterns? Just say the word.

Top comments (0)