Hoy es Cyberday

Cualquiera de nuestros cursos a 10 USD

Tomar un curso hoy mismo
Ejemplo de inyección de dependencia (DI) con PHP
Actualizado el 15 Septiembre, 2016 y leído 4,751 veces
Calificación: 10.00 / 10

Ejemplo de inyección de dependencia (DI) con PHP

Anexsoft

El objetivo de esta entrada es entender de manera saludable como funciona DI (dependecy injection) o inyección de dependencia en la tecnología PHP. Para esto he hecho un ejemplo muy sencillo el cual nos permita entender como funciona este patrón de diseño el cual, hoy en día es importante saberlo porque digamos que está de moda y lo encontrarán en la mayoría de los frameworks actuales ya que, su propia naturaleza permite que los proyectos sean más escalables y fácil de mantener.

 

Caso práctico

Somos analistas desarrolladores de una prestigiosa consultura de software y nos han pedido que hagamos el módulo de mailing, contamos con 3 proveedores los cuales son SendGrid, Malchimp y Mailgun, por lo cual podemos usar cualquiera de ellos. Bien hemos creado 3 clases para agilizar este proceso el cual hace referencia a cada proveedor, de esta manera sabremos con quien vamos a trabajar.

class MailChimp {
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>MailChimp</b> services from <b>$from</b> to <b>$to</b>";
    }
}

class Sengrid {
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>Sengrid</b> services from <b>$from</b> to <b>$to</b>";
    }
}

class MailGun {
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>MailGun</b> services from <b>$from</b> to <b>$to</b>";
    }
}

Caso #1 (Dependencia directa)

Nuestro cerebro por naturaleza haría algo como esto (considerando que no tienes conocimiento sobre DI). Si quisieramos trabajar con MailChimp, pues lo que haríamos es crear una instancia de MailChimp y usar los métodos que ofrece su API.

class Mailing {
    public function sendToUsers() {
        $eProvider = new MailChimp();
            
        $mails = ['erodriguezp105@gmail.com', 'user1@gmail.com', 'user2@gmail.com'];
        
        foreach($mails as $mail) {
            echo $eProvider->send('News from my website', $mail, 'admin@mywebsite.com') . '<br />';
        }
    }
}

$m = new Mailing();
$m->sendToUsers();

¿Que pasaría si quiero trabajar con MailGun o SendGrid?. Pues sería muy fácil, solo tendríamos que cambiar la instancia de nuestra clase, para nuestro ejemplo y por suerte, los métodos que implementan se llaman igual pero ....

¿Qué pasaría si fueran más métodos los que tenemos que usar?, ¿Qué no se llamen iguales? Es decir que no esten estandarizados, pués vá a pasar lo siguiente:

Tendremos que cambiar el código de nuestra lógica de negocio, en nuestro caso del método sendToUsers constantemente para cambiar de proveedor de correo.

Esto es una gran desventaja, porque hace que nuestro código sea más complicado de mantener y escalar.

 

Caso #2 (Dependecy Injection o DI)

Un poco de teoría ..

Inyección de dependencia: es un patrón de diseño muy usado hoy día con la finalidad de evitar tener dependencias directa en nuestro código, en vez de hacer una instancia directa lo que hacemos es trabajar con interfaces por lo cual evitamos tener que manipular nuestro código. Para nuestro ejemplo. Por ejm: si cambiamos de proveedor, nuestro código va a quedar igual no se va a ver afectado porque la dependencia la vamos a inyectar no instanciar como vimos en el caso #1.

A lo nuestro ..

Para esto vamos a tener que instalar un paquete de composer para que nos ayude con el manejo de nuestras dependencias. Corran el siguiente comando en su consola.

composer require php-di/php-di

 

Nuestro paquete se llama PHP-DI, el cual nos permite gestionar las dependencias de nuestros proyectos. Hasta aca seguro hemos comenzado mal y no entiendes nada, no importa, después de esta línea comenzarás a entender todo. En PHP para que funcione DI necesitamos un contenedor que guarde las dependencias, esto se conoce como Inversión de Control.

Inversión de control (IoC): imagínate que tu eres un actor y quieres trabajar en hollywood, lo que va a pasar es que te dirán (no nos llames, nosotros te llamaremos) y esto es lo que va a pasar con nuestro código. Nosotros no vamos a llamar a las dependencias, en nuestro caso a los proveedores de email, nuestro código nos va a enviar a nosotros los proveedores.

Ya mucho bla bla, yo se que tu quieres código, ahi vamos.

Creando nuestra interface

Primero vamos a crear una interface e implementar en la clase de nuestros proveedores.

interface IEmailProvider {
    public function send($subject, $to, $from);
}

class MailChimp implements IEmailProvider{
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>MailChimp</b> services from <b>$from</b> to <b>$to</b>";
    }
}

class Sengrid implements IEmailProvider{
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>Sengrid</b> services from <b>$from</b> to <b>$to</b>";
    }
}

class MailGun implements IEmailProvider{
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>MailGun</b> services from <b>$from</b> to <b>$to</b>";
    }
}

Lo que les dije, ya no vamos a trabajar directamente con las clases de nuestros proveedores, sino, con la interfaz.

Registrando nuestra dependencia con PHP-DI

El código es muy simple, si vamos a trabajar con MailGun lo especificamos en la instancia de nuestra dependencia En primer lugar hay cambios en nuestra clase Mailing.

class Mailing {
    private $eProvider;
        
    public function __CONSTRUCT(IEmailProvider $_eProvider) {
        $this->eProvider = $_eProvider;
    }
    
    public function sendToUsers() {
        $mails = ['erodriguezp105@gmail.com', 'user1@gmail.com', 'user2@gmail.com'];
        
        foreach($mails as $mail) {
            echo $this->eProvider->send('News from my website', $mail, 'admin@mywebsite.com') . '<br />';
        }
    }
}

$container = DI\ContainerBuilder::buildDevContainer();
$container->set('IEmailProvider', \DI\object('MailGun'));
$m = $container->get('Mailing');

$m->sendToUsers();

Luego tenemos que registrar nuestra dependencia con PHP-DI

require_once 'vendor/autoload.php';

$container = DI\ContainerBuilder::buildDevContainer();
$container->set('IEmailProvider', \DI\object('MailGun'));

Lo que estamos diciendo ahora es que la interface IEmailProvider esta asociada a MailGun (si quieren usar MailChimp o Sendgrid solo cambien el nombre de la clase). Ahora ya no podemos hacer una instancia directa de Mailing porque arrojaría un error ya que, su constructor espera un parámetro. Por eso, lo haremos ahora mediante PHP-DI.

$m = $container->get('Mailing');
$m->sendToUsers();

El resolverá el tema de dependencias.

En conclusión: hemos evitado cambiar el código de nuestra clase Mailing, cambiar de proveedor es una tarea sencilla.

 

Código completo

<?php
require_once 'vendor/autoload.php';

interface IEmailProvider {
    public function send($subject, $to, $from);
}

class MailChimp implements IEmailProvider{
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>MailChimp</b> services from <b>$from</b> to <b>$to</b>";
    }
}

class Sengrid implements IEmailProvider{
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>Sengrid</b> services from <b>$from</b> to <b>$to</b>";
    }
}

class MailGun implements IEmailProvider{
    public function send($subject, $to, $from) {
        return "<b>$subject</b> is sending an email using <b>MailGun</b> services from <b>$from</b> to <b>$to</b>";
    }
}

class Mailing {
    private $eProvider;
        
    public function __CONSTRUCT(IEmailProvider $_eProvider) {
        $this->eProvider = $_eProvider;
    }
    
    public function sendToUsers() {
        $mails = ['erodriguezp105@gmail.com', 'user1@gmail.com', 'user2@gmail.com'];
        
        foreach($mails as $mail) {
            echo $this->eProvider->send('News from my website', $mail, 'admin@mywebsite.com') . '<br />';
        }
    }
}

¡Adquiera ya!

  • Software de Portafolio Profesional hecho en ASP.NET MVC 5 C#

    Software de Portafolio Profesional hecho en ASP.NET MVC 5 C#
  • Software de Venta e Inventario hecho en PHP y Codeigniter

    Software de Venta e Inventario hecho en PHP y Codeigniter
  • Código de fuente de Red Social desarrollada en ASP.NET MVC

    Código de fuente de Red Social desarrollada en ASP.NET MVC

Últimas publicaciones

Encuesta

¿Cómo nos conociste?

Síguenos

Estudia con nosotros y crece profesionalmente

Nuestros cursos han sido hecho en base a lo que demanda el mercado hoy en día.
La experiencia obtenida es la de un ambiente laboral.

Anexsoft
© 2017 Anexsoft, blog y cursos online de TI.