Structural Design Patterns in PHP: Real-World Examples

WhoAmI => notes.sohag.pro/author
Search for a command to run...

WhoAmI => notes.sohag.pro/author
No comments yet. Be the first to comment.
Creational Design Patterns in PHP Introduction to Creational Design Patterns Design patterns are like the secret recipes of software development - they provide proven solutions to common design problems. Creational design patterns specifically focus ...
I had a solid list of reasons my life wasn't moving faster, until a grainy old lecture pointed out the one name missing from it

The finale isn't a victory lap. It's the story of the control I shipped that did nothing, the footgun still sitting in my demo, and the handful of things I'd keep exactly as they are.

How do you hold a large payment for a second pair of eyes without ever letting the unapproved money touch a balance, and how do you stream that decision to the outside world without standing up a broker?

How do you show the total under a parent account when the whole system refuses to store a balance? A recursive query, a trigger that refuses to draw a circle, and a rule about what actually has to sum to zero.

Every time I wanted to change an FX rate I had to edit a file on the server and restart the app. So I moved rates and markup into a live admin API, and then audited it hard enough to find the bug that quietly undid the whole thing.

Ever walked into a LEGO store? You'll see individual bricks that can be assembled into amazing structures. Structural design patterns in PHP work similarly โ they're blueprints that help us compose objects and classes into larger, more functional structures. Just as LEGO pieces need to fit perfectly together, these patterns ensure our code components work harmoniously.
Imagine you're building a house. You wouldn't start nailing boards together randomly โ you'd follow architectural plans. Similarly, structural design patterns are your architectural plans for writing better code. They help you:
Solve common design problems with proven solutions
Write more maintainable and flexible code
Communicate better with other developers
Save time by not reinventing the wheel
In this comprehensive guide, we'll explore five essential structural patterns:
Adapter Pattern - Like a universal power adapter that lets you charge your phone anywhere
Bridge Pattern - Think of a TV remote that works with any TV brand
Composite Pattern - Similar to how organizations structure their employees
Decorator Pattern - Like customizing your coffee with extra toppings
Facade Pattern - Think of a car dashboard simplifying complex engine operations
For each pattern, we'll:
Explain the concept using real-world analogies
Provide practical PHP code examples
Share everyday situations where you might use them
Discuss best practices and common pitfalls
PHP developers looking to level up their architecture skills
Team leads wanting to implement better coding standards
Anyone interested in writing more maintainable PHP code
Developers preparing for technical interviews
To get the most out of this guide, you should:
Have basic PHP knowledge
Understand object-oriented programming concepts
Be familiar with interfaces and inheritance
Let's dive in and explore how these patterns can transform your code from good to great! ๐
Travel Power Adapter
Your US laptop charger (120V) needs an adapter to work in Europe (230V)
The adapter converts without changing your device or the power outlet
Language Translator
A translator adapts one language to another
The original message remains the same, just converted to a different format
Card Reader
// Language Translator Example
interface EnglishSpeaker {
public function speakEnglish();
}
interface FrenchSpeaker {
public function speakFrench();
}
class FrenchPerson implements FrenchSpeaker {
public function speakFrench() {
return "Bonjour!";
}
}
class LanguageAdapter implements EnglishSpeaker {
private $frenchSpeaker;
public function __construct(FrenchSpeaker $speaker) {
$this->frenchSpeaker = $speaker;
}
public function speakEnglish() {
$french = $this->frenchSpeaker->speakFrench();
return ($french === "Bonjour!") ? "Hello!" : "Translation not found";
}
}
TV Remote Control
Same remote works with different TV brands
Volume up/down works consistently across brands
Car Controls
Steering wheel, pedals, gear shift work the same way across different car models
Different engines (electric, petrol) but same driving interface
Paint Brush and Colors
Same brush can be used with different colors
Different brush types can use the same colors
// Paint and Brush Example
interface Color {
public function getColor();
}
interface Brush {
public function paint();
}
class RedColor implements Color {
public function getColor() {
return "red";
}
}
class WatercolorBrush implements Brush {
protected $color;
public function __construct(Color $color) {
$this->color = $color;
}
public function paint() {
return "Painting with " . $this->color->getColor() . " watercolor";
}
}
Family Tree
Each family member can be an individual or have their own family
You can get information about a single person or an entire branch
File System
Files and folders are treated the same way
A folder can contain files or other folders
Shopping Cart with Packages
Individual items and bundles are treated as purchasable items
Calculate total price regardless of structure
// File System Example
interface FileSystem {
public function getSize(): int;
public function getName(): string;
}
class File implements FileSystem {
private $name;
private $size;
public function __construct(string $name, int $size) {
$this->name = $name;
$this->size = $size;
}
public function getSize(): int {
return $this->size;
}
public function getName(): string {
return $this->name;
}
}
class Folder implements FileSystem {
private $name;
private $contents = [];
public function add(FileSystem $item) {
$this->contents[] = $item;
}
public function getSize(): int {
return array_sum(array_map(fn($item) => $item->getSize(), $this->contents));
}
}
Coffee Customization
Start with basic coffee
Add milk, sugar, whipped cream, etc.
Each addition changes price and description
Pizza Toppings
Basic pizza crust
Add toppings: cheese, pepperoni, mushrooms
Each topping affects final price
Car Customization
Base model car
Add features: AC, leather seats, navigation
Each feature adds to total cost
// Pizza Example
interface Pizza {
public function getDescription(): string;
public function getCost(): float;
}
class BasicPizza implements Pizza {
public function getDescription(): string {
return "Basic pizza with tomato sauce";
}
public function getCost(): float {
return 8.00;
}
}
class CheeseDecorator implements Pizza {
private $pizza;
public function __construct(Pizza $pizza) {
$this->pizza = $pizza;
}
public function getDescription(): string {
return $this->pizza->getDescription() . ", mozzarella cheese";
}
public function getCost(): float {
return $this->pizza->getCost() + 2.50;
}
}
Restaurant Waiter
Waiter provides simple interface to complex kitchen system
You don't interact with cooks, dishwashers, or suppliers
Just order and receive food
Hotel Reception
Single point of contact for various services
Handles room service, housekeeping, maintenance
You don't need to know internal operations
Car Dashboard
Simple interface for complex car systems
Don't need to understand engine, electrical systems
// Restaurant Facade Example
class Kitchen {
public function cookFood(string $dish) {
return "Cooking $dish";
}
}
class Inventory {
public function checkIngredients(string $dish): bool {
return true; // Simplified
}
}
class Billing {
public function generateBill(string $dish): float {
return 15.00; // Simplified
}
}
class WaiterFacade {
private $kitchen;
private $inventory;
private $billing;
public function __construct() {
$this->kitchen = new Kitchen();
$this->inventory = new Inventory();
$this->billing = new Billing();
}
public function orderFood(string $dish): array {
$result = [];
if ($this->inventory->checkIngredients($dish)) {
$result['status'] = $this->kitchen->cookFood($dish);
$result['bill'] = $this->billing->generateBill($dish);
}
return $result;
}
}
// Usage
$waiter = new WaiterFacade();
$order = $waiter->orderFood("Pasta");
Choose based on your real-world scenario:
Use Adapter when:
Working with incompatible interfaces
Integrating third-party services
Need to convert data formats
Use Bridge when:
Need to switch implementations easily
Have cross-platform requirements
Want to separate interface from implementation
Use Composite when:
Dealing with tree structures
Need to treat groups and individuals uniformly
Building hierarchical menus
Use Decorator when:
Need to add features dynamically
Want flexible alternative to subclassing
Building customizable products
Use Facade when:
Simplifying complex systems
Creating unified API
Reducing system coupling
Remember: The best pattern is the one that solves your specific problem while keeping code maintainable and understandable. Don't force patterns where they're not needed!
Would you like to see more specific examples or explore any pattern in more detail?