Back to Blog
Lesson 27 of the PHP: Modern PHP from the Ground Up course
PHPAugust 14, 20264 min read

Refactoring to Classes: Mastering OOP for Code Quality in PHP

Learn how to elevate your PHP code by refactoring procedural logic into robust classes, improving maintainability, and reducing global scope dependencies.

PHPOOPrefactoringcode qualityprogramming patterns
A close-up view of PHP code displayed on a computer screen, highlighting programming and development concepts.

Previously in this course, we covered Classes and Objects: Mastering OOP Foundations in PHP and explored Visibility Modifiers: Mastering Encapsulation in PHP. While you now understand how to define a class, the real challenge lies in taking existing, messy procedural code and transforming it into a clean, object-oriented system.

In this lesson, we will focus on refactoring your existing scripts into classes to improve code quality and maintainability.

Moving Beyond Procedural Scripts

In the early stages of our project, we wrote procedural code—scripts that execute top-to-bottom, often relying on global variables and loose functions. While this is great for learning the basics, it becomes a maintenance nightmare as your application grows.

If you find yourself constantly passing the same $db connection or $config array into every function, you have a "global dependency" problem. Classes allow us to package data (properties) and behavior (methods) together, creating a self-contained unit of logic.

From Procedural Logic to Encapsulation

Let’s look at a common scenario: a procedural script that handles user authentication.

Procedural Approach:

PHP
#6A9955">// auth.php
$user = ['id' => 1, 'name' => 'John'];

function isLoggedIn($user) {
    return isset($user['id']);
}

function getWelcomeMessage($user) {
    return "Hello, " . $user['name'];
}

#6A9955">// Global usage
if (isLoggedIn($user)) {
    echo getWelcomeMessage($user);
}

This code is fine for a single file, but what if you need to perform these checks in ten different places? You’d have to pass the $user array everywhere. If the structure of $user changes, you have to update every single function.

The Refactored Object-Oriented Approach: We can group this logic into an AuthService class.

PHP
class AuthService {
    private array $user;

    public function __construct(array $user) {
        $this->user = $user;
    }

    public function isLoggedIn(): bool {
        return isset($this->user['id']);
    }

    public function getWelcomeMessage(): string {
        return "Hello, " . $this->user['name'];
    }
}

#6A9955">// Usage
$auth = new AuthService(['id' => 1, 'name' => 'John']);

if ($auth->isLoggedIn()) {
    echo $auth->getWelcomeMessage();
}

Why This Improves Quality

  1. Reduced Global Dependency: The $user data is encapsulated within the object. You no longer need to pass global arrays around your application.
  2. Predictability: The AuthService explicitly defines what it needs (the constructor) and what it can do (the methods).
  3. Maintainability: If you need to change how the welcome message is formatted, you only update one method inside the class.

Much like we discussed in Refactoring Monolithic Components: Mastering Code Quality, the goal is to decompose large, procedural blocks into specialized units. This practice is similar to the patterns used in Laravel refactoring: Move business logic into action classes, where we isolate specific responsibilities to keep our codebase clean.

Hands-on Exercise: Refactor Your Database Query

In our running MVC project, you likely have a procedural function or a loose block of code that fetches a user from the database.

  1. Identify a piece of code that connects to the database and fetches a single row.
  2. Create a class named UserProvider.
  3. Move the database connection and the query logic into a method inside this class.
  4. Instantiate the class and call your new method to retrieve the user data.

Common Pitfalls

  • Over-Engineering: Don't turn every single function into a class. If a piece of logic is used once and is very simple, a function is often perfectly acceptable.
  • Mixing Responsibilities: Avoid creating "God Classes" that handle authentication, database connections, and email sending all at once. Keep your classes focused—the Single Responsibility Principle.
  • Ignoring Visibility: Remember to use private or protected for properties that shouldn't be touched from the outside. If you leave everything public, you lose the benefits of encapsulation.

FAQ

Does refactoring to OOP make code faster? Not necessarily. In some cases, it may add a tiny overhead. However, the performance gain in developer productivity and bug reduction far outweighs the trivial cost of object instantiation.

When should I stop refactoring? Refactoring is an ongoing process. When your code is readable, testable, and changes in one place don't require updates in five other files, you have reached a healthy state.

Recap

Refactoring your procedural code into classes is the most significant step you can take toward building a professional-grade application. By grouping logic and hiding implementation details, you create a system that is easier to reason about and safer to expand.

Up next: We will begin Building the Controller Layer to orchestrate our application logic.

Similar Posts