Abe Estrada

Dependency Injection

Inyección de dependencias (en inglés Dependency Injection, DI) es un patrón de diseño orientado a objetos, en el que se suministran objetos a una clase en lugar de ser la propia clase la que cree dichos objetos. Esos objetos cumplen contratos que necesitan nuestras clases para poder funcionar (de ahí el concepto de dependencia). Nuestras clases no crean los objetos que necesitan, sino que se los suministra otra clase ‘contenedora’ que inyectará la implementación deseada a nuestro contrato.

— Wikipedia

En este ejemplo tenemos una computadora que necesita una forma de almacenamiento.

<?php
class Computer {
    protected $storage;

    public function __construct($storage) {
        $this->storage = new HardDrive();
    }
}

Ahí no tenemos flexbilidad ni inyección de dependencia, ya que la clase Computer crea una instancia de HardDrive dentro del constructor.

En el siguiente ejemplo podemos ver como se crea una inyección de dependencias.

<?php
class Computer {
    protected $storage;

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

$harddrive = new HardDrive();
$computer = new Computer($harddrive);

Esto da la flexibilidad de que si en algún momento queremos cambiar de método de almacenamiento, cambiamos la dependencia y e “inyectamos” la nueva, sin tener que modificar la clase base. Esto permite tener código reusable.

<?php
$ssddrive = new SSDDrive();
$computer = new Computer($ssddrive);

Otra opción además de inyectar las dependencias en el constructor, existe la posibilidad de crear un setter.

<?php
class Computer {
    protected $storage;

    public function setStorage($storage) {
        $this->storage = $storage;
    }
}

$harddrive = new HardDrive();
$computer = new Computer();
$computer->setStorage($harddrive);

Esta técnica utiliza el principio de diseño “Inversion of Control” (IoC por sus siglas en Inglés) o también conocido como el “Hollywood Principle” que dice: “No nos llames, nosotros te llamamos”, en el que las porciones personalizadas de un programa de computadora reciben el flujo de control desde un “framework” genérico.

Por supuesto que sería difícil gestionar las dependencias manualmente; por eso se necesita un contenedor de inyección de dependencias. Un contenedor de inyección de dependencias es algo que gestiona automáticamente las dependencias de su(s) clase(s). Frameworks como Laravel o Symfony, utilizan algún tipo de contenedor de inyección de dependencia.

Lo que los contenedores de inyección de dependencias hacen, es guardar una instancia de las dependencias y utilizarla cuando son requeridas, o crear una nueva instancia en caso de ser necesario, esto permite reutilizar las dependencias previamente declaradas.

<?php
class Container {
    protected $shared = [];
    protected $parameters = array();

    public function __construct(array $parameters = []) {
        $this->parameters = $parameters;
    }

    public function getStorage() {
        if (isset($this->shared["storage"])) {
            return $this->shared["storage"];
        }

        $class = $this->parameters["storage"];
        return $this->shared["storage"] = new $class();
    }
}

class Computer {
    protected $storage;

    public function __construct(Container $container) {
        $this->storage = $container->getStorage();
    }
}

$container = new Container([
    "storage" => "HardDrive"
]);
$computer = new Computer($container);

Ahora si, después de aprender la teoría y conocer como funcionar un sistema de inyección de dependencias, podemos utilizar una librería como PHP-DI (The dependency injection container for humans) para no tener que reinventar la rueda.