Design Patterns in PHP: Advanced Level
\n\nDesign patterns are proven solutions to typical problems that arise in software development. At the beginner level, developers learn Singleton, Factory, or Adapter. However, in complex, high-load, or flexible systems in PHP, more powerful and abstract patterns are required. In this article, we will cover four advanced patterns with real code examples in PHP: Strategy, Factory Method, Observer, and State.
\n\n1. Strategy Pattern
\n\nPurpose: Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Allows changing the behavior of an object at runtime without modifying its code.
\n\nExample: A payment processing system. We have several payment methods: credit card, PayPal, cryptocurrency. Each method has its own validation and processing logic.
\n\n<?php\n\n// Strategy interface\ninterface PaymentStrategy\n{\n public function pay(float $amount): void;\n public function validate(): bool;\n}\n\n// Concrete strategies\nclass CreditCardPayment implements PaymentStrategy\n{\n private string $cardNumber;\n private string $cvv;\n\n public function __construct(string $cardNumber, string $cvv)\n {\n $this->cardNumber = $cardNumber;\n $this->cvv = $cvv;\n }\n\n public function validate(): bool\n {\n // Simple check of card number length\n return strlen($this->cardNumber) === 16 && strlen($this->cvv) === 3;\n }\n\n public function pay(float $amount): void\n {\n if (!$this->validate()) {\n throw new \\InvalidArgumentException("Invalid card data");\n }\n echo "Paid {$amount} via credit card {$this->cardNumber}.<br>";\n }\n}\n\nclass PayPalPayment implements PaymentStrategy\n{\n private string $email;\n\n public function __construct(string $email)\n {\n $this->email = $email;\n }\n\n public function validate(): bool\n {\n return filter_var($this->email, FILTER_VALIDATE_EMAIL) !== false;\n }\n\n public function pay(float $amount): void\n {\n if (!$this->validate()) {\n throw new \\InvalidArgumentException("Invalid PayPal email");\n }\n echo "Paid {$amount} via PayPal ({$this->email}).<br>";\n }\n}\n\n// Context (client)\nclass OrderProcessor\n{\n private PaymentStrategy $strategy;\n\n public function setPaymentStrategy(PaymentStrategy $strategy): void\n {\n $this->strategy = $strategy;\n }\n\n public function processOrder(float $total): void\n {\n if (!isset($this->strategy)) {\n throw new \\RuntimeException("Payment method not selected");\n }\n $this->strategy->pay($total);\n }\n}\n\n// Usage\n$order = new OrderProcessor();\n$order->setPaymentStrategy(new CreditCardPayment('1234567812345678', '123'));\n$order->processOrder(150.00);\n// Output: Paid 150 via credit card 1234567812345678.\n\n?>\n\nAdvantages: Easily add new algorithms (new payment methods) without modifying existing code. The code becomes flexible and testable.
\n\n2. Factory Method Pattern
\n\nPurpose: Defines an interface for creating an object but allows subclasses to alter the type of object that will be created. This is the base pattern for all creational patterns.
\n\nExample: Generating different types of reports (PDF, HTML, JSON) depending on user request.
\n\n<?php\n\n// Abstract product\ninterface Report\n{\n public function generate(): string;\n}\n\n// Concrete products\nclass PdfReport implements Report\n