2

Inyección de dependencias en PHP

Félix
Felix
10178

En el curso se menciona que Laravel utiliza un patrón de diseño llamado “Inyección de Dependencias”, no lo conocía así que me puse a investigar de que se trata y aquí se los comparto para el que no sepa.

Si instancianciamos las dependencias de las clases dentro de ellas mismas, las clases son menos flexibles, y más difíciles de mantener a medida que estas escalan, si queremos reemplazar una dependencia debemos meternos en el código de ellas una por una. También es más difícil de testear porque no son bloques de código conteniendo solo lo que la clase debe tener, ya que también contiene código perteneciente a otras entidades, osea de las dependencias. Lo mejor es que en las clases haya código intrínseco a ellas.

Lo ideal es usar una patrón de diseño llamado “Inyección de dependencias”.

La inyección de dependencias es un método para escribir mejor código

La ventaja principal de la inyección de dependencias es el control, ya que el que está al comienzo de la cadena de llamadas a dependencias, siempre eres tú; te permite controlar todas las dependencias y controlar mucho mejor el funcionamiento de la aplicación. También puedes reemplazar una dependencia por otra con mayor facilidad.

En la práctica lo que se hace es crear interfaces para cada dependencia, estableciendo las funciones que deben implementar, estableciendo las funciones que luego usarán las clases que requieran esas dependencias. Esto asegura que si cambiamos una dependencia por otra similar, se mantengan las mismas funcionalidades y funciones que requieren las clases.

Una clase que implementa este patrón de diseño, debe requerir las dependencias como parámetros desde una función constructora, usando sus respectivas interfaces como declaración de tipo, para luego declararlas como propiedades de la clase.

=======================================

CASO EJEMPLO

Haremos una BaseDeDatos que como dependencia requiera un motor de base de datos, y que tenga la funcionalidad de imprimir los registros de una tabla.

Tendremos dos motores de base de datos, MySQL y PostgreSQL, la clase BaseDeDatos solo necesitaría usar uno, el punto es que podamos cambiar entre estos dos motores fácilmente.

En cada motor el proceso para obtener registros de una tabla es diferente, por lo que se declara una intefaz para los motores de base datos, que los obligue a tener una función para obtener los registros de una tabla (lo importante es que las dependencias tengan las mismas funciones y devuelvan el mismo resultado, aunque el proceso varíe, de esta forma podremos cambiar de dependencia fácilmente sin tener que cambiar el código interno de las clases que utilizan la dependencia).

Se declara la interfaz para la dependencia… (El motor de base de datos)

interfaceMotorBD{
     publicfunctionobtenerRegistrosDeTabla(string $nombreTabla);
}

Se declaran las dependencias implementando la intefaz…

classMySQLimplementsMotorBD{
     publicfunctionobtenerRegistrosDeTabla(string $nombreTabla){
          // Se devuelven los registros utilizando MySQL
     }
}

classPostgreSQLimplementsMotorBD{
     publicfunctionobtenerRegistrosDeTabla(string $nombreTabla){
          // Se devuelven los registros utilizando PostgreSQL
     }
}

Aquí la clase que requiere la dependencia, la insertaremos por el método constructor.

class BaseDeDatos
{
     protected $motor;

     public function __construct(MotorBD $motor)
     {
          $this->motor = $motor;
     }

     public function imprimirRegistrosDeTabla(string $nombreTabla)
     {
          // Obtener registros de la BD
          $this->motor->obtenerRegistrosDeTabla($nombreTabla);

          // Código para imprimir registros...
     }
}

Recordatorio: Las propiedades “protected” solo pueden ser accedidas desde la misma clase
o entidades heredadas de la clase

De esta forma podemos cambiar la dependencia sin alterar el código de la clase.

Ahora instanciamos “BaseDeDatos” inyectándole el motor que queramos…

Tenemos dos opciones:

$BD = new BaseDeDatos(new MySQL);

ó

$BD = new BaseDeDatos(new PostgreSQL);

Luego debería funcionar de la misma manera para las dos opciones…

$BD->imprimirRegistrosDeTabla('usuarios');

Adicionalmente existe un concepto llamado “Dependency Injector Container”, es una herramienta para ayudar a inyectar esas dependencias con mayor facilidad, agregando automatización al proceso, pero eso lo dejo para que lo investiguen por su cuenta.

Muchas gracias por su lectura! 😃

Escribe tu comentario
+ 2
1

Buenas tardes, cómo se puede desarrollar un contenedor de dependencias, separando obviamente la inyección de dependencia y el contenedor, en Php desde cero sin librerías ni extensiones de terceros.