Inyección de Dependencias en PHP: para principiantes
Imagina que estás armando una computadora. No sueldas el procesador directamente a la placa base para siempre — lo insertas en un zócalo especial para poder reemplazarlo por uno más potente si es necesario. La Inyección de Dependencias (DI) en PHP funciona bajo el mismo principio: en lugar de crear dependencias dentro de la clase, las «inyectas» desde el exterior.
En este artículo, analizaremos qué es la Inyección de Dependencias, para qué sirve y cómo aplicarla en PHP. Aprenderás cómo hacer que tu código sea flexible, comprobable y fácil de mantener.
¿Qué es la Inyección de Dependencias en palabras sencillas?
La Inyección de Dependencias es un patrón de diseño en el que un objeto recibe sus dependencias (otros objetos, servicios) desde el exterior, en lugar de crearlas él mismo. En lugar de escribir new Database() dentro de la clase, pasas un objeto de base de datos ya preparado a través del constructor o un setter.
Veamos el problema que resuelve DI. Considera la clase UserService, que crea directamente una conexión a la base de datos:
<?phpclass UserService { private $db; public function __construct() { // Acoplamiento rígido a una implementación específica $this->db = new MySQLConnection('localhost', 'user', 'pass'); } public function getUser($id) { return $this->db->query("SELECT * FROM users WHERE id = $id"); }}?>Los problemas de este enfoque son evidentes:
- Acoplamiento rígido (tight coupling) — la clase
UserServiceestá vinculada aMySQLConnection. Para cambiar a PostgreSQL, tendrías que modificar el código de la clase. - Dificultad para realizar pruebas — no podrás reemplazar la base de datos por un objeto mock en las pruebas unitarias.
- Violación del principio de responsabilidad única — la clase no solo se encarga de trabajar con usuarios, sino también de crear la conexión a la BD.
Ahora reescribamos esta clase usando la Inyección de Dependencias:
<?phpinterface DatabaseInterface { public function query($sql);}
class MySQLConnection implements DatabaseInterface { public function query($sql) { // Implementación para MySQL }}
class PostgreSQLConnection implements DatabaseInterface { public function query($sql) { // Implementación para PostgreSQL }}
class UserService { private $db; // La dependencia se inyecta a través del constructor public function __construct(DatabaseInterface $db) { $this->db = $db; } public function getUser($id) { return $this->db->query("SELECT * FROM users WHERE id = $id"); }}
// Uso$db = new MySQLConnection('localhost', 'user', 'pass');$userService = new UserService($db);?>Ahora UserService no sabe con qué base de datos específica está trabajando. Simplemente usa la interfaz DatabaseInterface. Esta es la esencia de la Inyección de Dependencias.
Tres tipos principales de inyección de dependencias
En PHP existen tres formas principales de inyectar dependencias. Veamos cada una de ellas.
1. Inyección a través del constructor (Constructor Injection)
Esta es la forma más común y recomendada. Las dependencias se pasan a través de los parámetros del constructor y se almacenan en propiedades privadas de la clase.
<?phpclass Logger { private $writer; public function __construct(LogWriterInterface $writer) { $this->writer = $writer; } public function log($message) { $this->writer->write($message); }}?>Ventajas: las dependencias son claramente visibles, el objeto siempre está en un estado válido (todas las dependencias son obligatorias).
Desventajas: e