CreationalPHPverifiedVerified
Abstract Factory Pattern in PHP
Provides an interface for creating families of related objects without specifying their concrete classes.
How to Implement the Abstract Factory Pattern in PHP
1Step 1: Define product interfaces for the UI component family
interface Button
{
public function render(): string;
}
interface Checkbox
{
public function render(): string;
}2Step 2: Define the abstract factory interface
interface UIFactory
{
public function createButton(): Button;
public function createCheckbox(): Checkbox;
}3Step 3: Implement concrete products for each theme
class DarkButton implements Button
{
public function render(): string { return '<button class="dark">Click</button>'; }
}
class DarkCheckbox implements Checkbox
{
public function render(): string { return '<input type="checkbox" class="dark"/>'; }
}
class LightButton implements Button
{
public function render(): string { return '<button class="light">Click</button>'; }
}
class LightCheckbox implements Checkbox
{
public function render(): string { return '<input type="checkbox" class="light"/>'; }
}4Step 4: Implement concrete factories that produce consistent families
class DarkThemeFactory implements UIFactory
{
public function createButton(): Button { return new DarkButton(); }
public function createCheckbox(): Checkbox { return new DarkCheckbox(); }
}
class LightThemeFactory implements UIFactory
{
public function createButton(): Button { return new LightButton(); }
public function createCheckbox(): Checkbox { return new LightCheckbox(); }
}5Step 5: Client code works with the factory abstraction
function renderUI(UIFactory $factory): void
{
$button = $factory->createButton();
$checkbox = $factory->createCheckbox();
echo $button->render() . "\n" . $checkbox->render() . "\n";
}
renderUI(new DarkThemeFactory());<?php
declare(strict_types=1);
// [step] Define abstract product interfaces for database access
interface ConnectionInterface
{
public function connect(): void;
public function disconnect(): void;
public function isConnected(): bool;
}
interface QueryBuilderInterface
{
public function select(string $table, array $columns = ['*']): self;
public function where(string $column, string $operator, mixed $value): self;
public function build(): string;
}
interface TransactionInterface
{
public function begin(): void;
public function commit(): void;
public function rollback(): void;
}
// [step] Define the abstract factory
interface DatabaseFactoryInterface
{
public function createConnection(array $config): ConnectionInterface;
public function createQueryBuilder(): QueryBuilderInterface;
public function createTransaction(ConnectionInterface $connection): TransactionInterface;
}
// [step] Implement MySQL family
final class MySqlConnection implements ConnectionInterface
{
private bool $connected = false;
public function __construct(private readonly array $config) {}
public function connect(): void { $this->connected = true; }
public function disconnect(): void { $this->connected = false; }
public function isConnected(): bool { return $this->connected; }
}
final class MySqlQueryBuilder implements QueryBuilderInterface
{
private string $table = '';
/** @var string[] */
private array $columns = ['*'];
/** @var string[] */
private array $conditions = [];
public function select(string $table, array $columns = ['*']): self
{
$clone = clone $this;
$clone->table = $table;
$clone->columns = $columns;
return $clone;
}
public function where(string $column, string $operator, mixed $value): self
{
$clone = clone $this;
$escaped = is_string($value) ? "'{$value}'" : (string) $value;
$clone->conditions[] = "{$column} {$operator} {$escaped}";
return $clone;
}
public function build(): string
{
$cols = implode(', ', $this->columns);
$sql = "SELECT {$cols} FROM {$this->table}";
if (!empty($this->conditions)) {
$sql .= ' WHERE ' . implode(' AND ', $this->conditions);
}
return $sql;
}
}
final class MySqlTransaction implements TransactionInterface
{
public function __construct(private readonly ConnectionInterface $connection) {}
public function begin(): void { /* START TRANSACTION */ }
public function commit(): void { /* COMMIT */ }
public function rollback(): void { /* ROLLBACK */ }
}
// [step] Implement PostgreSQL family
final class PostgresConnection implements ConnectionInterface
{
private bool $connected = false;
public function __construct(private readonly array $config) {}
public function connect(): void { $this->connected = true; }
public function disconnect(): void { $this->connected = false; }
public function isConnected(): bool { return $this->connected; }
}
final class PostgresQueryBuilder implements QueryBuilderInterface
{
private string $table = '';
private array $columns = ['*'];
private array $conditions = [];
public function select(string $table, array $columns = ['*']): self
{
$clone = clone $this;
$clone->table = $table;
$clone->columns = $columns;
return $clone;
}
public function where(string $column, string $operator, mixed $value): self
{
$clone = clone $this;
$paramIndex = count($clone->conditions) + 1;
$clone->conditions[] = "\"{$column}\" {$operator} \${$paramIndex}";
return $clone;
}
public function build(): string
{
$cols = implode(', ', array_map(fn(string $c) => "\"{$c}\"", $this->columns));
$sql = "SELECT {$cols} FROM \"{$this->table}\"";
if (!empty($this->conditions)) {
$sql .= ' WHERE ' . implode(' AND ', $this->conditions);
}
return $sql;
}
}
final class PostgresTransaction implements TransactionInterface
{
public function __construct(private readonly ConnectionInterface $connection) {}
public function begin(): void { /* BEGIN */ }
public function commit(): void { /* COMMIT */ }
public function rollback(): void { /* ROLLBACK */ }
}
// [step] Concrete factories
final class MySqlFactory implements DatabaseFactoryInterface
{
public function createConnection(array $config): ConnectionInterface
{
return new MySqlConnection($config);
}
public function createQueryBuilder(): QueryBuilderInterface
{
return new MySqlQueryBuilder();
}
public function createTransaction(ConnectionInterface $connection): TransactionInterface
{
return new MySqlTransaction($connection);
}
}
final class PostgresFactory implements DatabaseFactoryInterface
{
public function createConnection(array $config): ConnectionInterface
{
return new PostgresConnection($config);
}
public function createQueryBuilder(): QueryBuilderInterface
{
return new PostgresQueryBuilder();
}
public function createTransaction(ConnectionInterface $connection): TransactionInterface
{
return new PostgresTransaction($connection);
}
}Abstract Factory Pattern Architecture
hourglass_empty
Rendering diagram...
lightbulb
Abstract Factory Pattern in the Real World
“Imagine furnishing a room from IKEA versus a luxury boutique. Each store (factory) produces a complete set of furniture — chairs, tables, sofas — that share a consistent style. You pick the store, and every piece you get matches. You never mix a rustic IKEA chair with a baroque boutique table.”