Veremos qué es y como utilizar este patrón de diseño en PHP.
En la progrmación orientada a objetos, un programa central normalmente controla otros objetos, ya sea en un modulo, una librería o un framework. Con la inyección de dependencia, este patrón es invertido, ya que una referencia hacia una clase es incluida directamente en el objecto, el cual será facilmente testeable, estará desacoplado y tendrá modularidad.
La inyección de dependencia (Dependency Injection en inglés) es una técnica, o mejor dicho, un patrón de diseño de software en lenguajes orientados a objetos, para incluir o abastecer una dependencia externa (por ejemplo, una librería third-party) en alguna clase de nuestro proyecto, con lo cual, se le indica a esta clase que otras clases puede usar. La DI es una forma específica de inversión de control.
En resumén, DI significa darle a un objeto la instancia de otro objeto para que este último pueda ser utilizado.
Veamos un ejemplo en PHP.
Para manejar las variables de sesión de PHP crearemos una clase llamada SessionHandler:
<?php class SessionHandler { function __construct($cookieName = 'hasheado') { session_name($cookieName); session_start(); } function setAttibute($key, $value) { $_SESSION[$key] = $value; } function getAttribute($key) { return $_SESSION[$key]; } // ... } ?>
Y una clase User para manejar la información pertinente al usuario:
<?php class User { protected $handler; function __construct() { $this->handler = new SessionHandler(); } function setLanguage($language) { $this->handler->setAttribute('language', $language); } function getLanguage() { return $this->handler->getAttribute('language'); } // ... } ?>
El uso de estas clases es bastante sencillo:
<?php $user = new User(); $user->setLanguage('es'); $user_language = $user->getLanguage(); ?>
Hasta ahora todo el código luce correcto y bien. Hasta que necesitamos más flexibilidad. Por ejemplo, que pasa si quisieramos cambiar el nombre de la cookie de session. Repasemos algunas posibilidades:
Por ejemplo, podemos hardcodear el nombre de la cookie en el constructor de la clase User:
<?php class User { function __construct() { $this->handler = new SessionHandler('hasheado'); } // ... } ?>
También podríamos definir una constante fuera de la clase User:
<?php class User { function __construct() { $this->handler = new SessionHandler(HANDLER_SESSION_NAME); } // ... } define('HANDLER_SESSION_NAME', 'hasheado'); ?>
O podríamos pasar el nombre de la sesión como un argumento del constructor:
<?php class User { function __construct() { $this->handler = new SessionHandler($sessionName); } // ... } $user = new User('hasheado'); ?>
Como quizás ya te habras dado cuenta todas estas opciones son malas. Hardcodear el nombre de la sesión en la clase User no resuelve el problema de cambiar facilmente el nombre sin modificar la clase User. Usar una constante es una muy mala idea ya que ahora la clase User depende de esta constante. Y pasar el nombre de la sesión como un argumento es quizás la mejor opción, pero sigue viendose mal.
Además, todavía hay otro problema que no puede ser resuelto facilmente: Cómo podemos cambiar la clase SessionHandler para remplazarla por un objeto mock con propositos de testing, ó si queremos almacenar las sesiones en la base de datos o en memoria. Todo eso es imposible con la actual implementación, excepto si cambiamos la clase User.
Implementemos Dependency Injection. En vez de crear el objeto SessionHandler dentro de la clase User inyectaremos el objeto SessionHandler en el objeto User pasándoselo como un argumento en el constructor:
<?php class User { function __construct($handler) { $this->handler = $handler; } // ... } ?>
Esto es Dependency Injection. Y usar la clase User ahora es dependiente del objeto SessionHandler:
<?php $handler = new SessionHandler('hasheado'); $user = new User($handler); ?>
Ahora, configurar el objeto SessionHandler es mucho más simple, y remplazar esta clase también es bastante fácil. Y todo esto es posible sin tener que modificar la clase User.
Existen varias maneras de implementar Dependency Injection, como vimos anteriormente una de estas maneras es el Constructor Injector:
<?php class User { function __construct($handler) { $this->handler = $handler; } // ... } ?>
Otra manera es el Setter Injector:
<?php class User { function setSessionHandler($handler) { $this->handler = $handler; } // ... } ?>
Y aún otra manera es el Property Injector:
<?php class User { public$sessionHandler; } $user->sessionHandler = $handler; ?>
La manera más recomendada para implementar dependencias requeridas es Constructor Injection, y la mejor opción para implementar dependencias opcionales es Setter Injection.
Bien eso es todo, hoy en día la mayoría de los frameworks PHP más modernos usan altamente Dependency Injection para proveer un conjunto de componentes desacoplados pero cohesivos. Espero que les quede claro el concepto de Dependency Injection.
Fuente: Fabien Potencier's blog


1 Comentario:
marcelog:
20 de Febrero de 2011 a las 02:52:36Ding (http://marcelog.github.com/Ding) es un container con inversion of control y dependency injection que imita a spring(tm) de java en su funcionalidad, tambien implementa algunas annotations de jsr 250 y 330