INYECCIÓN DE DEPENDENCIAS EN PHP

Antes de explicar la inyección de dependencias hay que explicar el concepto de inversión de control que se puede definir como el proceso donde los objetos son suministrados a las clases que los necesitan, en lugar de crearlos ellos mismos. esto se puede ver fácilmente con un ejemplo sencillo:

class Newsletter {
  protected $mail ;
  function __construct() {
    $this -> mail = New Mailer ('correo@gmail.com', ...) ;
  }
}
Esta clase, para enviar correos, que todos implementaríamos, tiene un problema ya que se está creando una dependencia muy fuerte entre la clase Newsletter y la clase Mail. Una solución sería, aplicando la inversión de control:

class Newsletter {
  protected $mail;
  function __construct() {
    $this -> mail = $mail;
  }
}
La solución propuesta es pasarle un objeto completamente configurado y preparado para enviar correos eliminando esa fuerte dependencia que existía entre las dos clases.
Ahora mismo estarás pensando que el problema no está solucionado todavía, que todavía has tenido que crear ese objeto Mail, configurarlo a mano y pasárselo a cada objeto que lo requiera. ¡Vamos paso a paso! La inyección de dependencias es un patrón de diseño, que trata de solucionar las necesidades de creación de los objetos de una manera práctica, útil, escalable y con una alta versatilidad del código y que nuestros objetos sean independientes comunicándose únicamente a través de un interface. Esto implica muchas modificaciones en el código fuente como el uso de implementaciones, la eliminación de la instanciación de objetos mediante la instrucción new o la necesidad de un modo de configuración que indique que clases se instanciarán en el caso de solicitarlo.
Para mostrar la inyección de dependencias en la práctica, vamos a ver un ejemplo muy sencillo. En este caso tenemos una clase llamada Database que requiere de un adaptador para poder comunicarse con la base de datos. En la primera versión del código se instancia el adaptador en el mismo constructor de la clase, lo que crea una dependencia muy fuerte entre estas dos partes del código. ësto hace que si en un futuro se necesita un cambio haya que cambiar el código.
Aquí tienes un ejemplo claro de inyección de dependencias en PHP, usando un enfoque basado en el constructor:

interface StorageInterface {
    public function save(string $data): void;
}
Se crea el interfaz, para implementar los diferentes tipos de almacenamiento posible (storage) y luego se crean las diferentes classes:

// Implementación concreta de almacenamiento en archivo
class FileStorage implements StorageInterface {
    public function save(string $data): void {
   echo "Guardando '$data' en un archivo.\n";
   // Lógica para guardar en archivo
    }
}

// Implementación concreta de almacenamiento en base de datos
class DatabaseStorage implements StorageInterface {
    public function save(string $data): void {
   echo "Guardando '$data' en la base de datos.\n";
   // Lógica para guardar en BD
    }
}

Una vez creado el interfaz y las clases que dependen de ella es cuando se usa la inyección de dependencias

// Implementación concreta de almacenamiento en archivo
class UserService {
    private $storage;

    // Inyección de dependencia a través del constructor
    public function __construct(StorageInterface $storage) {
   $this->storage = $storage;
    }

    public function saveUser(string $userData): void {
   $this->storage->save($userData);
    }
}
    $fileStorage = new FileStorage();
    $userServiceWithFile = new UserService($fileStorage);
    $userServiceWithFile->saveUser("Usuario1"); // Guardando 'Usuario1' en un archivo.

    // Inyectamos DatabaseStorage
    $dbStorage = new DatabaseStorage();
    $userServiceWithDb = new UserService($dbStorage);
    $userServiceWithDb->saveUser("Usuario2"); // Guardando 'Usuario2' en la base de datos.
En el ejemplo anterior se ve que al "userService" se le pasa "$fileStorage = new FileStorage();" y el "$dbStorage = new DatabaseStorage();" para guardar los datos según nos interese.