¿Qué es Dependency Injection en PHP y por qué es necesaria?
\n\nImagina que estás construyendo una casa. En lugar de fabricar tú mismo cada ladrillo, simplemente los pides y usas los ya hechos. Dependency Injection (DI) en programación funciona bajo el mismo principio: no creas objetos dentro de la clase, sino que los recibes desde fuera. Esto hace que tu código sea flexible, comprobable y comprensible.
\n\nEn PHP, como en cualquier lenguaje orientado a objetos, las clases a menudo dependen de otras clases. El problema surge cuando las dependencias se crean directamente dentro de la clase; esto se llama acoplamiento rígido (tight coupling). Dependency Injection resuelve este problema pasando las dependencias desde el exterior.
\n\nEl problema sin Dependency Injection
\nConsideremos un ejemplo típico donde la clase UserService crea ella misma el objeto de base de datos:
<?php\nclass Database {\n public function query($sql) {\n // Lógica de la consulta\n return "Resultado: " . $sql;\n }\n}\n\nclass UserService {\n private $db;\n \n public function __construct() {\n // Acoplamiento rígido: la clase crea su propia dependencia\n $this->db = new Database();\n }\n \n public function getUser($id) {\n return $this->db->query("SELECT * FROM users WHERE id = $id");\n }\n}\n\n$service = new UserService();\necho $service->getUser(1);\n?>\n\nProblemas de este enfoque:
\n- \n
- No se puede reemplazar
Databasepor otra implementación (por ejemplo, para pruebas) \n - Difícil de probar: no se puede inyectar un simulacro (mock) \n
- El código se vuelve monolítico y difícil de ampliar \n
Solución: Inyección de dependencia a través del constructor
\nAhora reescribamos la misma clase usando Dependency Injection:
\n\n<?php\nclass UserService {\n private $db;\n \n // La dependencia se pasa desde el exterior\n public function __construct(Database $db) {\n $this->db = $db;\n }\n \n public function getUser($id) {\n return $this->db->query("SELECT * FROM users WHERE id = $id");\n }\n}\n\n// Creamos la dependencia por separado\n$database = new Database();\n$service = new UserService($database);\necho $service->getUser(1);\n?>\n\nAhora UserService no sabe cómo se crea Database. Simplemente usa lo que le pasaron. Esto es inyección de dependencia.
Tipos de Dependency Injection en PHP
\nExisten tres formas principales de inyectar dependencias. Veamos cada una con ejemplos.
\n\n1. Inyección por constructor (Constructor Injection)
\nLa forma más común y recomendada. Las dependencias se pasan al crear el objeto a través del constructor.
\n\n<?php\nclass Logger {\n public function log($message) {\n echo "[LOG]: " . $message;\n }\n}\n\nclass OrderProcessor {\n private $logger;\n \n // Dependencia en el constructor\n public function __construct(Logger $logger) {\n $this->logger = $logger;\n }\n \n public function process($order) {\n // Procesamiento del pedido\n $this->logger->log("Pedido procesado: " . $order);\n }\n}\n\n$logger = new Logger();\n$processor = new OrderProcessor($logger);\n$processor->process("Pedido #123");\n?>\n\nVentajas: la dependencia siempre está disponible, el objeto siempre está en un estado válido. Desventajas: si hay muchas dependencias, el constructor puede volverse voluminoso.
\n\n2. Inyección por setter (Setter Injection)
\nSe usa cuando la dependencia puede ser opcional o necesita ser reemplazada durante la vida del objeto.
\n\n<?php\nclass MailService {\n private $transport;\n \n // Setter para la dependencia\n public function setTransport($transport) {\n $this->transport = $transport;\n }\n \n public function send($to, $mess