← Tilbage til koncepter
Dependency Injection
Inversion of Control pattern til løs kobling mellem components
Kategori: Design Patterns
Foto: Benjamin Smith / Unsplash
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