Sigo explorando las novedades de PHP 5.3 y, entre ellas están las llamadas dinámicas a métodos estáticos, según he visto en esta interesante presentación de Ilia Alshanetsky. Veamos un ejemplo:
class Aplicacion { public static function getVersion() { return "1.2"; } } $metodo = "getVersion"; Aplicacion::$metodo(); //Devuelve "1.2"
Se ve claramente que podemos llamar a un método estático cuyo nombre no definimos al escribir el código, sino que está en una variable. Esta característica ya estaba disponible en versiones anteriores de la rama PHP 5, tanto para clases como para métodos, pero no estáticos:
class Conexion { public function conectar($servidor, $usuario, $clave) { echo "Mira Mamá, me estoy conectando!"; } } $clase = "Conexion"; $método = "conectar"; $objeto = new $clase(); $objeto->$método("localhost", "pepito", "grill0"); //Imprimirá "Mira Mamá, me estoy conectando!"
Bueno, y esta característica parece interesante, pero ¿cómo podemos aplicarla a la vida real? Uno de los ejemplos más claros que se me ocurre es la implementación del patrón de diseño Strategy. En este sencillo patrón se trata de cargar una u otra implementación de una clase dependiendo de alguna variable o acción del usuario. Por ejemplo, imaginemos que queremos conectarnos a bases de datos Oracle o MySQL, según qué servicio escoja el usuario desde un formulario. Primero definimos una clase abstracta Conexion que declare los métodos que las implementaciones han de desarrollar, y escribimos sendas clases hijas para Oracle y MySQL:
abstract class Conexion { private $recurso; public function conectar($usuario, $clave) { } } class ConexionOracle { public function conectar($usuario, $clave) { $this->recurso = oci_connect($usuario, $clave); } } class ConexionMysql { public function conectar($usuario, $clave) { $this->recurso = mysql_connect("localhost", $usuario, $clave); } } /* * $_POST['dbms'] proviene de un cuadro desplegable (option select) en que se * da a escoger entre oracle y mysql. * ucfirst() pone en mayúscula la primera letra */ $conector = "Conexion" . ucfirst($_POST['dbms']); $instancia = new $conector; try { $instancia->conectar($_POST['usuario'], $_POST['clave']); } catch (Exception $e) { echo "Lo siento, pero por algún motivo la conexión ha fallado"; }
En fin, esto es todo, creo que es evidente la potencia de esta característica del lenguaje, que viene a intentar evitar el uso de eval() y dar al lenguaje un poco más de elegancia, al estilo del class.forName() de Java. Por cierto, para una descripción más profunda del patrón Strategy te recomiendo este interesante artículo de Jack Herrington sobre patrones implementados en PHP.
Pues sí, Strategy es un patrón estúpidamente sencillo, pero en el ejemplo y en otros muchos casos (como en Multivista) encaja perfectamente.
Los otros que has nombrado son para problemas más complejos, serán interesante que nos instruyas en ellos
Por cierto, acerca del Observer, en PHP existen los métodos mágicos __clone(), __call(), etc de los que hablaré en breve, que pueden implementar de forma transparente el lanzamiento de eventos que propone este patrón. Por ejemplo, implementar el __call() en una clase abstracta que permitiría capturar llamadas a métodos de las clases hijas.
Siempre me ha sorprendido el patrón Strategy (al igual que el State). Ya que no deja de ser una simple herencia.
Es verdad que todos se basan en herencia pero con algo más de molla; véase abstract factory, composite, decorator, …
Pero la pregunta clave es, a nivel de clases que intervienen, ¿que diferencia hay entre el strategy y el state?