Novedades PHP 5.3 (III) – Nuevo Singleton – Design Patterns

Seguimos con los posts sobre las novedades de PHP 5.3 y en este post empezaremos a ver cómo estas mejoras afectan o mejoran los patrones de diseño clásicos.

Los patrones de diseño son un conjunto de soluciones a problemas comunes en el desarrollo de aplicaciones informáticas. Hace años, casi nadie los usaba en aplicaciones web, pero con el crecimiento de Internet y de sus aplicaciones se ve necesario seguir una serie de patrones.

Para empezar, hablaremos del patrón Singleton y las diferencias entre PHP 5.2 y PHP 5.3. El patrón Singleton sirve para aquellos objetos en los cuales solamente tenemos una instancia en cada ejecución de nuestra aplicación. Ejemplos claros de ello pueden ser la conexión a la base de datos, la gestión de logs de la aplicación, en muchas ocasiones los modelos de un diseño MVC, etc.

Singleton en PHP 5.2

<?php
class DB {
    private static $_instance = null;
 
    private function  __construct() {
        // Aquí pondríamos la lógica de conexión a la BBDD
        // con PDO, mysql_connect, etc...
    }
 
    public static function getInstance() {
       if(self::$_instance === null) {
           self::$_instance = new DB();
       }
       return self::$_instance;
    }
    // Si no hacemos un override del metodo __clone,
    // podríamos tener más de una instancia
    final public function __clone() {
        throw new Exception('Only one instance is allowed');
    }
}
 
// Desde cualquier punto del código
$db = DB::getInstance();
 
// Sin el override de __clone, podríamos hacer
$db2 = clone $db;
// Y $db2 sería otro objeto de tipo DB
?>

Esto está muy bien y el código queda bastante mono pero tiene un problema. Si queremos hacer nuevos singleton en nuestra aplicación, deberemos repetir en todos ellos la lógica del getInstance, el override de __clone y todos estos temas o bien hacer algunas cosas raras. Y esto va en contra del principio DRY (Don’t Repeat Yourself!).

En PHP 5.3, afortunadamente, y ligado con el tema de los Late Static Bindings (ver post al respecto) existe la función get_called_class que nos da en un contexto static cuál es el nombre de la clase llamado. Y diréis… ¿y esto para qué narices sirve? Vamos a verlo!

Singletons en PHP 5.3 con get_called_class

<?php
abstract class Singleton {
    private static $_instances = array();
 
    final private function  __construct() {        
        // Por si acaso, controlamos que no exista ya
        if(array_key_exists(get_called_class(), self::$_instances)) {
            throw new Exception('Already one instance of '.get_called_class());
        }
        static::initialize();
    }
    // Método abstracto para inicializar cada singleton
    abstract protected static function initialize();
 
    final public static function getInstance() {
       $class = get_called_class();
       if(!array_key_exists($class, self::$_instances)) {
           self::$_instances[$class] = new $class();
       }
       return self::$_instances[$class];
    }
    final public function __clone() {
        throw new Exception('Class type ' . get_called_class() . ' cannot be cloned');
    }
}
 
class DB extends Singleton {
    protected static function initialize() {        
        // Aquí realizaríamos la conexión a la BBDD con el método que queramos
    }
}
 
class Log extends Singleton {
    protected static function initialize() {
        // Aquí trataríamos el log de la aplicación con gestión de directorios y archivos
    }
}
 
$db = DB::getInstance(); // Initializing DB
$log = Log::getInstance(); // Initializing Log
$db2 = clone $db; // Exception!
 
 
?>

Tenemos una clase abstracta singleton que controla las instancias únicas de todas ellas mediante un array static.
En cada clase que hereda de la abstracta, ya podemos olvidarnos del control de instancia única y solamente será necesario definir el método initialize y así las clases tendrán solamente aquellos métodos diferentes y no todo el control de singleton.

Y además, como dice mi amigo Raúl, queda bonito! 🙂

Próximamente… anonymous functions y arrays en la certificación! Y otros patrones!

You may also like...