Factory Design Pattern in PHP

Factory Design Pattern

When developing complex applications, managing object creation can become chaotic. The Factory Method design pattern in PHP offers a clean solution by delegating the instantiation logic to child classes. This helps decouple your code, reduce duplication, and simplify unit testing.

Let’s explore what this pattern is, when to use it, and how it improves code maintainability. We’ll compare a bad code example with a clean implementation using the Factory Method design pattern in PHP.

Bad Code: Tight Coupling and Duplicated Logic

Here’s a typical anti-pattern where object creation is scattered and hard-coded:

class Notification {

    public function send($type) {
        if ($type === 'email') {
            $notifier = new EmailNotifier();
        } elseif ($type === 'sms') {
            $notifier = new SmsNotifier();
        } else {
            throw new Exception("Unknown notifier type.");
        }

        $notifier->sendMessage();
    }
}

class EmailNotifier {

    public function sendMessage() {
        echo "Sending email notification...";
    }
}

class SmsNotifier {

    public function sendMessage() {
        echo "Sending SMS notification...";
    }
}

What’s wrong here?

  • Each time you add a new notification type, you modify Notification.
  • Violates the Open/Closed Principle.
  • Hard to unit test because object creation is tightly bound.

Good Code: Using the Factory Method Design Pattern in PHP

Let’s refactor this using the pattern in PHP:

// Product interface
interface Notifier {
    public function sendMessage(): void;
}


// Concrete Products
class EmailNotifier implements Notifier {
    public function sendMessage(): void {
        echo "Sending email notification...";
    }
}


class SmsNotifier implements Notifier {
    public function sendMessage(): void {
        echo "Sending SMS notification...";
    }
}


// Creator (abstract class)
abstract class NotificationFactory {
    abstract public function createNotifier(): Notifier;

    public function notify(): void {
        $notifier = $this->createNotifier();
        $notifier->sendMessage();
    }
}


// Concrete Creators
class EmailNotificationFactory extends NotificationFactory {
    public function createNotifier(): Notifier {
        return new EmailNotifier();
    }
}


class SmsNotificationFactory extends NotificationFactory {
    public function createNotifier(): Notifier {
        return new SmsNotifier();
    }
}


// Client code
$factory = new EmailNotificationFactory();
$factory->notify(); // Outputs: Sending email notification...

Why Use this Design Pattern in PHP?

The Factory Method design pattern in PHP promotes flexibility and separation of concerns. Rather than directly instantiating classes, you delegate this responsibility to subclasses that determine which object to create.

Here’s what makes it powerful:

  • Extensibility: Add new notifiers without modifying existing logic.
  • Testability: Easily mock or stub factories during testing.
  • Maintainability: Cleaner and more organized codebase.

When your project grows, managing class dependencies becomes crucial. Instead of letting object creation spiral out of control, you harness a structured pattern to handle it. That’s the beauty of the Factory Method.

When Should You Use It?

Use the Factory Method pattern when:

  • Your code needs to create objects without specifying their exact class.
  • You anticipate new types of products (e.g., new notification channels).
  • You want to adhere to the SOLID principles, especially the Open/Closed Principle.

Final Thought

This design pattern is a simple yet powerful tool to help organize your code. By deferring instantiation to child classes, you gain a more modular, testable, and maintainable codebase. Whether you’re building a notification system or a plugin loader, Factory Method helps reduce coupling and promotes clean architecture.

Interested in More Design Patterns?

Discover other powerful patterns like Factory, Strategy, and Observer in this full guide:

➡️ Design Patterns in PHP – The Complete Guide to All Types