El patrón de diseño Singleton (implementado en PHP)

Vamos con la entrada número 400 del blog, y la 200 de informática. Curioso, llegados a este punto de casi dos años bloggeando un tema que no era el principal ha acabado ocupando el 50% del contenido del blog.

En fin, seguimos con los patrones de diseño. El otro día hablaba del patrón Decorator, hoy vamos con el Singleton.

La idea del patrón Singleton, también llamado de instancia única, es restringir la creación de objetos pertenecientes a una clase a sólo uno. Garantiza que sólo hay una instancia y proporciona un único punto de acceso.

La idea es que la clase tenga un constructor privado para que no pueda ser accedido desde fuera de la clase y que aunque haya clases hijas estas no puedan instanciar objetos. También debe tener una propiedad estática privada donde almacenaremos nuestra instancia y un método estático que sea el punto de acceso global a la misma, devolviéndola cuando se lo llama.

Vamos con el ejemplo típico y tópico del objeto de base de datos, que suele ser el uso más común de este tipo de clases. Porque crear varias instancias de acceso a una base de datos en la mayoría de los casos es un malgasto de recursos, lo mejor suele ser tener una sola instancia para realizar las conexiones.

class Database {
//Propiedad estática, inicializada a nulo, donde guardaremos la instancia de la propia clase
    static private $instance = null;
//Definimoms el método constructor como privado
    private function __contruct() {}
     
//Método estatico que sirve como punto de acceso global
    public static function getInstance() {
        if (self::$instance == null) {
//Si no hay instancia creada, lo hace. Si la hay tira p'alante
            self::$instance = new Database();
        }
//Al final devuelve la instancia
        return self::$instance;
    }
	     
 //a continuación ya meterías todas las funciones necesarias para un objeto de base de datos. CRUD, etc...
}

Y ya est… No, sorry man pero no. Con el código así todavía es posible que alguien logre hacer más de una instancia. Y te dirás ¿cómo? Pues porque todavía es posible usar la clonación y la serialización para lograrlo. Cosa mala, pero con los métodos mágicos de PHP5 podemos arreglarnos.

Para evitar la cuestión de la clonación definimos el método mágico __clone() en la clase, para que en lugar de permitir el clonado del objeto nos lance un error y detenga el script:

public function __clone()
{
  trigger_error("No puede clonar una instancia de ". get_class($this) ." class.", E_USER_ERROR );
}

Y vamos con el tema de la serialización y deserialización. Con la función serialize() se puede almacenar una representación apta de una variable (y una instancia de un objeto es, al fina, una variable) mientras que con unserialize() podemos acceder a ella como se si tratara de un clon. De nuevo hay que redefinir un método mágico, en concreto esta vez __wakeup(), que es el método que se invoca al deserializar un objeto. De esa forma se evita que pueda ser accedido. También podría hacerse con __sleep(), que es el que se invoca al serializar, pero veo más práctico evitar la deserialización.

public function __wakeup()
{
  trigger_error("No puede deserializar una instancia de ". get_class($this) ." class.", E_USER_ERROR );
}

En fin, he caído en el ejemplo tópico, pero también me pareció el más claro. Un saludo, disfruta este articulo 400.

Un comentario en “El patrón de diseño Singleton (implementado en PHP)

  1. Agustín Sardón

    Muy bueno. Yo me aproximaba pero dejaba flecos sin cubrir (constructor privado y vacio, clon, unserialice) O sea, como en tu primera ventana de código. Lo he implementado en una clase Conexion que obtiene una conexión a la base de datos. Para las consultas tengo otras clases que requieren de ésta. Muchas gracias por el aporte.

Replica a Agustín Sardón Cancelar la respuesta

Este sitio utiliza Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.