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
EasyLet'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 aDocumentinterface that defines the contract all document types must follow. It should have a single methodrender(string $content): stringthat takes content and returns the formatted document output.Documents.php— Include the Document interface and create three classes that implement it:PdfDocument— Itsrender()method returns"PDF: [content]"HtmlDocument— Itsrender()method returns"<html>[content]</html>"TextDocument— Itsrender()method returns"TXT: [content]"
DocumentFactory.php— Include the Documents file and create aDocumentFactoryclass with a static methodcreate(string $type): Document. This method should usematchto return the appropriate document object based on the type:"pdf"returns a newPdfDocument"html"returns a newHtmlDocument"text"returns a newTextDocument- Any other type should throw an
InvalidArgumentExceptionwith 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"
?>This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe $this KeywordMethodsPropertiesConstructor (__construct)Destructor (__destruct)Recap - Simple Calculator4Inheritance
Basic InheritanceThe parent:: KeywordMethod OverridingThe final KeywordAbstract ClassesRecap - Employee Hierarchy7Encapsulation
Public, Protected, PrivateAccess Modifiers in DepthGetters and SettersInformation HidingConstructor Promotion (8.0)Recap - Student Records System2Namespaces & Autoloading
Introduction to NamespacesThe use KeywordPSR-4 Autoloading StandardComposer AutoloaderRecap - Organized Project5Interfaces & Contracts
Introduction to InterfacesImplementing InterfacesMultiple Interface ImplementInterface vs Abstract ClassType Hinting with InterfacesRecap - Shape Calculator8Magic Methods
Magic Methods Introduction__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Object Cloning__serialize & __unserializeRecap - Custom Collection11Type System & Error Handling
Type DeclarationsNullable TypesUnion & Intersection TypesException ClassesCustom Exception HierarchyTry, Catch, FinallyRecap - Form Validator14Project: Library Management
Project OverviewBook and User Classes3Class Properties
Instance vs Static PropertiesConstants in ClassesStatic Methods & PropertiesPrivate & Protected PropertiesReadonly Properties (PHP 8.1)Recap - Bank Account Manager6Polymorphism
Method Overriding RevisitedPolymorphism via InterfacesType Hinting & Union TypesLate Static BindingRecap - Payment Processor9Traits
Introduction to TraitsUsing Multiple TraitsTrait Conflict ResolutionAbstract Methods in TraitsTraits vs Inheritance12Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern