PHP and Object-Oriented Programming
Design Patterns in the Wild
Patterns you use every day without knowing their names
You Already Use Design Patterns
Design patterns are named solutions to recurring problems. You don't need to memorize the Gang of Four book, but recognizing the patterns Laravel uses helps you understand why the framework is structured the way it is — and when to apply the same patterns in your own code.
Facade Pattern
When you write Cache::get('key') or DB::table('users'), you're using the Facade pattern. A facade provides a static-like interface to an object resolved from the service container.
Cache isn't a class with a static get() method. It's a facade that:
- Intercepts the static call via PHP's
__callStatic()magic method. - Resolves the underlying cache manager from the service container.
- Forwards the method call to the resolved instance.
Facades are syntactic sugar for dependency injection. Cache::get('key') is equivalent to app('cache')->get('key'). They're convenient but hide dependencies — in service classes, prefer injecting the actual interface.
Observer Pattern
Laravel's event system is the Observer pattern. Objects emit events; listeners observe and react to those events:
// Dispatching an event
OrderPlaced::dispatch($order);
// Listening (in EventServiceProvider)
OrderPlaced::class => [
SendConfirmationEmail::class,
UpdateInventory::class,
NotifyWarehouse::class,
]
Eloquent model events (creating, updating, deleting) are also Observer pattern implementations. The Observer class you can generate with php artisan make:observer hooks into model lifecycle events.
Strategy Pattern
The Strategy pattern defines a family of algorithms and makes them interchangeable. In Laravel:
- Cache drivers — File, Redis, Memcached, Database. Same interface, different strategies.
- Queue drivers — Sync, Database, Redis, SQS.
- Mail drivers — SMTP, Postmark, SES, Mailgun.
- Session drivers — File, Cookie, Database, Redis.
Each driver implements the same interface but uses a different algorithm. You switch strategies by changing a config value — your application code doesn't change at all.
Builder Pattern
The Builder pattern constructs complex objects step by step. Laravel's query builder is the classic example:
$users = DB::table('users')
->where('active', true)
->where('role', 'admin')
->orderBy('name')
->limit(10)
->get();
Each method call returns the builder itself (method chaining), adding a constraint to the query being constructed. The get() call at the end triggers execution. Eloquent's query scopes follow the same pattern.
Key Takeaways
- Facades provide static-like access to container-resolved objects. Convenient but hide dependencies.
- Observer (Events/Listeners) decouples actions from reactions. Use it when multiple things should happen in response to one event.
- Strategy makes algorithms interchangeable. Every Laravel driver system uses this pattern.
- Builder constructs complex objects step by step. The query builder and Eloquent scopes are prime examples.
Ask me anything about this lesson.
I have the full lesson content as context.