← Tilbage til koncepter
Dependency Injection
Inversion of Control pattern til løs kobling mellem components
Kategori: Design Patterns
🎯 Key Points
- ✓Constructor injection - Injicér dependencies gennem constructor (mest common)
- ✓Setter injection - Injicér dependencies gennem setter methods (optional dependencies)
- ✓Interface injection - Dependencies implementerer et interface for injection
- ✓Service containers - Centralt registry til håndtering af dependencies og deres lifecycle
- ✓Dependency Inversion Principle - Depend on abstractions (interfaces) ikke concrete classes
- ✓Auto-wiring - Automatisk resolution af dependencies baseret på type hints
- ✓Service providers - Register bindings mellem interfaces og implementations
- ✓Singleton vs Transient - Lifecycle management af injected objects
- ✓Method injection - Injicér dependencies direkte i method calls
- ✓Container configuration - Definér hvordan dependencies skal resolves
💻 Kode Eksempel
<?php
// Step 1: Define interfaces (abstractions)
interface LoggerInterface {
public function log(string $message, array $context = []): void;
}
interface UserRepositoryInterface {
public function find(int $id): ?User;
public function save(User $user): bool;
}
// Step 2: Concrete implementations
class FileLogger implements LoggerInterface {
public function __construct(
private string $logPath
) {}
public function log(string $message, array $context = []): void {
$timestamp = date('Y-m-d H:i:s');
$contextStr = json_encode($context);
file_put_contents(
$this->logPath,
"[{$timestamp}] {$message} {$contextStr}" . PHP_EOL,
FILE_APPEND
);
}
}
class DatabaseUserRepository implements UserRepositoryInterface {
public function __construct(
private PDO $database
) {}
public function find(int $id): ?User {
$stmt = $this->database->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$id]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
return $data ? new User($data['id'], $data['name'], $data['email']) : null;
}
public function save(User $user): bool {
// Implementation here
return true;
}
}
// Step 3: Service with injected dependencies
class UserService {
public function __construct(
private UserRepositoryInterface $repository,
private LoggerInterface $logger
) {}
public function getUser(int $id): ?User {
$this->logger->log('Fetching user', ['id' => $id]);
$user = $this->repository->find($id);
if ($user) {
$this->logger->log('User found', ['user_id' => $id]);
} else {
$this->logger->log('User not found', ['user_id' => $id]);
}
return $user;
}
}
// Step 4: Manual dependency injection (without container)
$pdo = new PDO('mysql:host=localhost;dbname=myapp', 'user', 'pass');
$logger = new FileLogger('/var/log/app.log');
$repository = new DatabaseUserRepository($pdo);
$userService = new UserService($repository, $logger);
$user = $userService->getUser(123);💼 Hvornår bruges det?
- •Testing - Mock dependencies i unit tests uden at ændre production kode
- •Framework architecture - Laravel og Symfony bruger DI til at wire hele applikationen
- •Swappable implementations - Skift mellem FileLogger og DatabaseLogger uden at ændre consumer kode
- •Configuration management - Injicér configuration objects frem for hardcoded values
- •Third-party service integration - Injicér API clients som dependencies for nem testing
- •Multi-tenancy - Injicér tenant-specific dependencies baseret på context
⭐ Best Practices
- ✓Prefer constructor injection for required dependencies - gør dependencies eksplicitte
- ✓Type hint interfaces ikke concrete classes - følg Dependency Inversion Principle
- ✓Brug setter injection kun for optional dependencies der har reasonable defaults
- ✓Keep constructors simple - lav ikke kompleks logik i constructors med DI
- ✓Brug service containers til at manage complex dependency graphs automatisk
- ✓Document service bindings klart - hvilke interfaces er bundet til hvilke implementations
- ✓Avoid service locator anti-pattern - injicér dependencies direkte, ikke containeren
- ✓Use auto-wiring når muligt for at reducere manuel configuration
ℹ️ Quick Info
Kategori
Design Patterns
Sværhedsgrad
Mellem til Avanceret