Dependency Injection
Also Known As
DI
inversion of control
IoC
dependency inversion
TL;DR
Passing dependencies into a class rather than creating them inside — makes classes testable and loosely coupled.
Explanation
Dependency injection (DI) means a class receives its collaborators (database connection, mailer, logger) as constructor arguments or method parameters rather than instantiating them internally with new. This makes the class testable (you can pass mock collaborators in tests), configurable (swap implementations without changing the class), and loosely coupled (the class depends on an interface, not a concrete implementation). Constructor injection is the preferred form — it makes dependencies explicit and the class impossible to create in an invalid state.
Diagram
flowchart LR
subgraph Without_DI
CLASS2[UserService creates its own<br/>new DatabaseConnection<br/>new EmailClient]
TIGHT[Tightly coupled<br/>untestable<br/>hardcoded deps]
end
subgraph With_DI
CONSTR[Constructor injection<br/>deps passed in]
IFACE[Depend on interface<br/>not concrete class]
CONSTR & IFACE --> LOOSE[Loosely coupled<br/>testable<br/>swappable]
end
subgraph Container
IOC[IoC Container<br/>auto-resolves dependencies]
BIND[bind interface to implementation]
IOC --> BIND
end
style TIGHT fill:#f85149,color:#fff
style LOOSE fill:#238636,color:#fff
style IOC fill:#6e40c9,color:#fff
Common Misconception
✗ Dependency injection requires a DI container or framework. DI is simply passing dependencies in rather than constructing them internally — constructor injection with no framework at all is valid DI and often simpler for smaller codebases.
Why It Matters
DI makes dependencies explicit and swappable — you can substitute a real mailer for a fake one in tests, or swap a Redis cache for an in-memory one without touching business logic. Code without DI is hard to test and tightly coupled.
Common Mistakes
- Injecting the container itself (service locator anti-pattern) — inject specific dependencies instead.
- Using constructor injection for optional dependencies — use setter injection or nullable defaults for those.
- Newing up dependencies inside methods (new Mailer()) instead of receiving them from outside.
- Registering everything as a singleton when it should be transient, causing state leakage between requests.
Code Examples
✗ Vulnerable
class OrderService {
public function place(Cart $cart): Order {
$mailer = new Mailer(); // hard-coded dependency
$db = new Database(); // impossible to swap/mock
$db->save($cart);
$mailer->send($cart->user, 'Your order is placed');
}
}
✓ Fixed
class OrderService {
public function __construct(private MailerInterface $mailer) {}
public function notify($order) {
$this->mailer->send($order->email, 'Order confirmed');
}
}
References
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
13 Mar 2026
Edited
22 Mar 2026
Views
31
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
Perplexity 11
Amazonbot 6
Unknown AI 3
Ahrefs 2
SEMrush 2
Google 2
Majestic 1
Also referenced
How they use it
crawler 25
crawler_json 1
pre-tracking 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: Medium
⚡ Quick Fix
Inject dependencies through the constructor rather than creating them with 'new' inside the class — this decouples the class from its dependencies
📦 Applies To
PHP 5.0+
web
cli
queue-worker
laravel
symfony
🔗 Prerequisites
🔍 Detection Hints
new SomeService() or new PDO() inside a class method or constructor body
Auto-detectable:
✓ Yes
phpstan
psalm
semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium
False Positives: High
✗ Manual fix
Fix: High
Context: Class
Tests: Update