Ray.Di Study: Practical Object-Oriented Design Patterns
This study teaches which pattern solves which problem. Using Ray.Di, you will deepen your practical understanding of SOLID principles and design patterns, and build the judgement to create maintainable and extensible architectures.
Learning focus
- From problem to pattern: Solve problems such as tight coupling, bloated controllers, and mixed data access with the right pattern
- Decision criteria: Learn when to use a Factory, when to use a Strategy, and when to use a Repository
- Practical SOLID: Understand single responsibility, open/closed, and dependency inversion through real code
- Architecture design: Layer separation, separation of concerns, and module design
- Compile-time decisions: Replace runtime
ifstatements ($_ENVchecks, type checks) with DI bindings to reduce code paths and achieve the open/closed principle
This tutorial focuses on learning design patterns. For the Ray.Di feature reference, see the manual.
Tutorial structure
Part 1: Foundations - Why DI matters
Problem: Tight coupling, hard to test, fragile to change What you learn: How dependency injection and SOLID principles solve these problems
- Dependency Injection Principles - Inversion of control and loose coupling
- SOLID Principles in Practice - Understanding the five principles through real code
- Ray.Di Fundamentals - Bringing Google Guice’s ideas to PHP
Part 2: Object creation patterns
Problem: Bloated constructors, runtime parameters, optional dependencies What you learn: Decision criteria for separating object creation responsibilities
- Factory Pattern - When to use: when object creation needs runtime parameters
- Provider Pattern - When to use: when initialization is complex
- Null Object Pattern - When to use: when handling optional dependencies without null checks
Part 3: Behavioral patterns
Problem: Exploding conditionals, scattered cross-cutting concerns What you learn: How to make behavior switchable and separate concerns
- Strategy Pattern - When to use: when switching algorithms at runtime
- Decorator Pattern & AOP - When to use: when separating logging, transactions, and similar concerns
Part 4: Architecture patterns
Problem: Mixed data access, bloated controllers, bloated DI configuration What you learn: Architecture design that separates layers and clarifies responsibilities
- Adapter Pattern - When to use: when adapting an external API or library
- Repository Pattern - When to use: when separating data access from business logic
- Service Layer - When to use: when coordinating business logic
- Module Design - When to use: when DI configuration has more than 50 bindings
Learning approach
Each section follows a consistent structure:
- Problem - A concrete issue in real code (10-20 lines)
- Why it matters - Impact on maintainability, testability, and extensibility
- Solution - The core implementation of the pattern (30-50 lines)
- The essence of the pattern - Visual understanding through diagrams
- Decision criteria - When to use this pattern and when not to
- Anti-patterns - Common mistakes and why they happen
- Relation to SOLID - The principles this pattern realizes
Where to start
For OOP beginners Recommended order: Dependency Injection Principles → SOLID Principles → Factory Pattern
For experienced developers You can start anywhere. Each section is independent.
For architects Recommended: SOLID Principles → Architecture patterns
Key patterns covered
| Pattern | Problem it solves | When to use it |
|---|---|---|
| Factory | Mixing runtime parameters with DI dependencies | When object creation needs runtime values |
| Provider | Bloated constructors | When complex initialization logic is needed |
| Null Object | Scattered null and environment checks | When optional dependencies vary by environment |
| Strategy | Exploding conditionals | When switching algorithms at runtime |
| Decorator/AOP | Scattered cross-cutting concerns | When separating logging, transactions, and similar concerns |
| Adapter | Mismatch between an external API and the application | When adapting an external service to the application |
| Repository | Mixed data access | When separating data access from business logic |
| Service Layer | Bloated controllers | When coordinating business logic |
| Module Design | Bloated DI configuration | When there are more than 50 bindings |
Prerequisites
- A basic understanding of OOP
- Knowledge of interfaces
Additional resources
- Ray.Di manual - Feature reference
- Ray.Di GitHub
- Design Patterns in PHP
Start: Dependency Injection Principles
Design patterns are not something to memorize - understanding the decision criteria is what matters. This tutorial will help you develop the judgement to choose the right pattern for each situation.