mailer->sendMail($recipient, 'Notification', $message); } } // ============================================================================= // Example 3: Infrastructure Adapters // ============================================================================= interface CacheAdapter { public function get(string $key): mixed; public function set(string $key, mixed $value, int $ttl = 3600): void; public function delete(string $key): void; } /** * Redis cache adapter * Automatically becomes the default cache implementation */ #[DefaultImplementation(CacheAdapter::class)] final readonly class RedisCacheAdapter implements CacheAdapter { public function __construct( private RedisConnection $redis ) {} public function get(string $key): mixed { return $this->redis->get($key); } public function set(string $key, mixed $value, int $ttl = 3600): void { $this->redis->setex($key, $ttl, $value); } public function delete(string $key): void { $this->redis->del($key); } } // ============================================================================= // Example 4: HTTP Client Abstraction // ============================================================================= interface HttpClient { public function get(string $url, array $headers = []): HttpResponse; public function post(string $url, array $data, array $headers = []): HttpResponse; } /** * Guzzle-based HTTP client * Auto-detects HttpClient interface */ #[DefaultImplementation] final readonly class GuzzleHttpClient implements HttpClient { public function __construct( private \GuzzleHttp\Client $guzzle ) {} public function get(string $url, array $headers = []): HttpResponse { $response = $this->guzzle->get($url, ['headers' => $headers]); return new HttpResponse($response->getStatusCode(), (string) $response->getBody()); } public function post(string $url, array $data, array $headers = []): HttpResponse { $response = $this->guzzle->post($url, [ 'headers' => $headers, 'json' => $data ]); return new HttpResponse($response->getStatusCode(), (string) $response->getBody()); } } // ============================================================================= // Example 5: Multiple Interfaces (Auto-detect First) // ============================================================================= interface EventLogger { public function logEvent(string $event, array $context): void; } interface Flushable { public function flush(): void; } /** * File-based event logger with flush capability * Auto-detects EventLogger (first interface) */ #[DefaultImplementation] // Binds to EventLogger, not Flushable final readonly class FileEventLogger implements EventLogger, Flushable { public function __construct( private string $logFilePath ) {} public function logEvent(string $event, array $context): void { file_put_contents( $this->logFilePath, json_encode(['event' => $event, 'context' => $context]) . "\n", FILE_APPEND ); } public function flush(): void { file_put_contents($this->logFilePath, ''); } } // ============================================================================= // Example 6: Using Default Implementations // ============================================================================= /** * Service that depends on default implementations */ final readonly class UserService { public function __construct( private UserRepository $userRepository, // DatabaseUserRepository injected private NotificationService $notifications, // EmailNotificationService injected private CacheAdapter $cache // RedisCacheAdapter injected ) {} public function registerUser(string $email, string $name): void { // Check cache first $cachedUser = $this->cache->get("user:$email"); if ($cachedUser !== null) { return; // User already registered } // Create and save user $user = new User($email, $name); $this->userRepository->save($user); // Cache the user $this->cache->set("user:$email", $user, 3600); // Send notification $this->notifications->send($email, "Welcome to our platform, $name!"); } } // ============================================================================= // Example 7: Advanced - Combining with Initializers // ============================================================================= interface PaymentGateway { public function charge(int $amountInCents, string $token): PaymentResult; } /** * Stripe payment gateway * Requires complex initialization via Initializer */ #[DefaultImplementation(PaymentGateway::class)] final readonly class StripePaymentGateway implements PaymentGateway { public function __construct( private StripeApiClient $stripeClient ) {} public function charge(int $amountInCents, string $token): PaymentResult { return $this->stripeClient->createCharge($amountInCents, $token); } } /** * Initializer for StripeApiClient * Runs after DefaultImplementation registration */ final readonly class StripeInitializer { #[\App\Framework\DI\Initializer] public function initializeStripeClient(): StripeApiClient { $apiKey = $_ENV['STRIPE_SECRET_KEY'] ?? throw new \RuntimeException('Missing Stripe API key'); return new StripeApiClient($apiKey, [ 'api_version' => '2023-10-16', 'timeout' => 30 ]); } } // ============================================================================= // Usage in Application // ============================================================================= /** * The container automatically resolves all dependencies: * * $container->get(UserService::class) * -> UserRepository (DatabaseUserRepository) * -> NotificationService (EmailNotificationService) * -> CacheAdapter (RedisCacheAdapter) * * All instances are singletons - same instance returned on subsequent calls */ // ============================================================================= // Stub Classes (for example completeness) // ============================================================================= class User { public function __construct( public string $email, public string $name ) {} } class DatabaseConnection {} class MailerService { public function sendMail(string $to, string $subject, string $body): void {} } class RedisConnection { public function get(string $key): mixed { return null; } public function setex(string $key, int $ttl, mixed $value): void {} public function del(string $key): void {} } class HttpResponse { public function __construct( public int $statusCode, public string $body ) {} } class StripeApiClient { public function __construct(string $apiKey, array $options) {} public function createCharge(int $amount, string $token): PaymentResult { return new PaymentResult(true, 'ch_123'); } } class PaymentResult { public function __construct( public bool $success, public string $transactionId ) {} }