Menu
Coddy logo textTech

Factory Pattern

Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 72 of 91.

The Factory Pattern is a creational design pattern that delegates object creation to a separate class or method. Instead of using new directly throughout your code, you ask a factory to create objects for you.

This pattern is particularly useful when you have multiple related classes that share a common interface, and you want to decide which one to instantiate based on some condition. Consider a notification system that can send messages via different channels:

<?php
interface Notification {
    public function send(string $message): string;
}

class EmailNotification implements Notification {
    public function send(string $message): string {
        return "Email: $message";
    }
}

class SmsNotification implements Notification {
    public function send(string $message): string {
        return "SMS: $message";
    }
}

Without a factory, you'd scatter if statements and new calls everywhere. The factory centralizes this logic:

<?php
class NotificationFactory {
    public static function create(string $type): Notification {
        return match($type) {
            'email' => new EmailNotification(),
            'sms' => new SmsNotification(),
            default => throw new InvalidArgumentException("Unknown type: $type")
        };
    }
}

$notification = NotificationFactory::create('email');
echo $notification->send('Hello!');

Output:

Email: Hello!

The key benefit is that your code depends on the Notification interface, not concrete classes. If you later add a PushNotification class, you only update the factory. All code using the factory automatically gains access to the new type without modification.

challenge icon

Challenge

Easy

Let's build a document generator system using the Factory Pattern. Different document types (PDF, HTML, Plain Text) share a common interface but produce different outputs — a perfect scenario for centralizing object creation in a factory.

You'll organize your code across four files:

  • Document.php — Create a Document interface that defines the contract all document types must follow. It should have a single method render(string $content): string that takes content and returns the formatted document output.
  • Documents.php — Include the Document interface and create three classes that implement it:
    • PdfDocument — Its render() method returns "PDF: [content]"
    • HtmlDocument — Its render() method returns "<html>[content]</html>"
    • TextDocument — Its render() method returns "TXT: [content]"
  • DocumentFactory.php — Include the Documents file and create a DocumentFactory class with a static method create(string $type): Document. This method should use match to return the appropriate document object based on the type:
    • "pdf" returns a new PdfDocument
    • "html" returns a new HtmlDocument
    • "text" returns a new TextDocument
    • Any other type should throw an InvalidArgumentException with the message "Unknown document type: [type]"
  • main.php — Include the DocumentFactory file. You'll receive two inputs: a document type and the content to render.

    Use the factory to create the appropriate document type, then call its render() method with the content and print the result.

    On a new line, print "Factory benefit: Adding new types only requires updating the factory" to highlight why this pattern is valuable.

The Factory Pattern keeps your code flexible — when you need to add a MarkdownDocument later, you'll only update the factory while all existing code continues to work unchanged.

Cheat sheet

The Factory Pattern delegates object creation to a separate class or method instead of using new directly throughout your code.

This pattern is useful when you have multiple related classes sharing a common interface, and you need to decide which one to instantiate based on a condition.

Example with a notification system:

<?php
interface Notification {
    public function send(string $message): string;
}

class EmailNotification implements Notification {
    public function send(string $message): string {
        return "Email: $message";
    }
}

class SmsNotification implements Notification {
    public function send(string $message): string {
        return "SMS: $message";
    }
}

The factory centralizes object creation logic:

<?php
class NotificationFactory {
    public static function create(string $type): Notification {
        return match($type) {
            'email' => new EmailNotification(),
            'sms' => new SmsNotification(),
            default => throw new InvalidArgumentException("Unknown type: $type")
        };
    }
}

$notification = NotificationFactory::create('email');
echo $notification->send('Hello!'); // Output: Email: Hello!

Key benefits:

  • Code depends on the interface, not concrete classes
  • Adding new types only requires updating the factory
  • Existing code automatically gains access to new types without modification

Try it yourself

<?php
require_once 'DocumentFactory.php';

// Read input
$type = trim(fgets(STDIN));
$content = trim(fgets(STDIN));

// TODO: Use DocumentFactory to create the appropriate document type
// TODO: Call the render() method with the content and print the result
// TODO: On a new line, print "Factory benefit: Adding new types only requires updating the factory"

?>
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming