viernes, 29 de marzo de 2013

Cómo implementar el patrón de diseño Singleton en PHP

El patrón de diseño Singleton es creado para asegurarse de tener solamente una instancia de un objeto durante la ejecución de un hilo en un proceso determinado. Un ejemplo típico de esto es tener una instancia del objeto de conexión a la base de datos. Para mayores referencias sobre este patrón de diseño, pueden ir a la wikipedia.

Bien, me voy a enfocar a explicar cómo implementarlo en php, el cual con esta ténica es soportada a partir de php 5.0+ pues en versiones anteriores el manejo de ciertos métodos mágicos no funcionaría.


<?php

/**
 * Description of Singleton
 *
 * @author Ultiminio Ramos
 */
class Singleton
{

    private static $instancia;
    private $_contador;

    /**
     * Declaramos private el método constructor, para evitar acceder a él cada vez
     * que se realiza la instanciación de esta clase
     */
    private function __construct()
    {
        echo 'Se ha instanciado una clase (<code style="color: blue; font-weight: bolder;">' . __CLASS__ . "</code>)< br/>";

        $this->_contador = 0;
    }

    /**
     * Punto global de acceso a la clase, pues el método constructor lo hemos
     * declarado como private para asegurarnos de que no se puede acceder a él
     * sino solamente por medio de este método llamado getInstance()
     * 
     * @return object
     */
    public static function getInstance()
    {
        if (!self::$instancia instanceof self) {
            self::$instancia = new self;
        }

        return self::$instancia;
    }

    /**
     * Método público que ya es accesible desde un objeto instanciado
     */
    public function incrementar()
    {
        return ++$this->_contador;
    }

    /**
     * Método público que ya es accesible desde un objeto instanciado
     */
    public function disminuir()
    {
        return --$this->_contador;
    }

    /**
     * Método mágico que nos permite gestionar la clonación y evitar que se rompa
     * el patrón singleton
     */
    public function __clone()
    {
        $error_msg = 'No se permite la clonación dentro del patrón singleton';
        $error_msg.= '(<code style="color: blue;">' . get_class($this) . '</code>)';

        //trigger_error($error_msg, E_USER_NOTICE); # mandamos un mensaje, pero la ejecución no se interrumpe
        trigger_error($error_msg, E_USER_ERROR); # interrumpimos la ejecución
    }

    /**
     * Método mágico para gestionar la serialización y por consiguiente 
     * evitar romper el patrón singleton
     */
    public function __wakeup()
    {
        $error_msg = 'No se permite la serialización dentro del patrón singleton';
        $error_msg.= '(<code style="color: blue;">' . get_class($this) . '</code>)';

        trigger_error($error_msg, E_USER_ERROR); # interrumpimos la ejecución
    }

}

Ahora, es momento de probar nuestro patrón de diseño.

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Probar el patrón Singleton en PHP 5.0+</title>
    </head>
    <body>
        <?php
        include_once 'app/test_singleton/model/Singleton.php';

        $br = '< br/>'; 

        $instancia = Singleton::getInstance();
        echo '<pre>';
        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;
        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;
        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;
        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;
        echo 'instancia(++$i) = ' . ($instancia->incrementar()) . $br;
        echo '<hr/>';

        # probar la clonación como técnica para romper el patrón singleton
        $clone = clone($instancia);

        echo 'clone_instancia(--$i) = ' . $clone->disminuir() . $br;
        echo 'clone_instancia(--$i) = ' . $clone->disminuir() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
        echo 'clone_instancia(++$i) = ' . $clone->incrementar() . $br;
   
        # probar la serialización/deserialización como técnica para romper el patrón singleton
        $serializado = serialize($instancia);
        $unserializa = unserialize($serializado);
        echo '$unserializa(++$i) = ' . $unserializa->incrementar() . $br;
        echo '$unserializa(++$i) = ' . $unserializa->incrementar() . $br;
        echo '$unserializa(++$i) = ' . $unserializa->incrementar() . $br;
        echo '$unserializa(++$i) = ' . $unserializa->incrementar() . $br;

        # comprobación
        echo '.' . $br;
        echo '.' . $br;
        echo '.' . $br;

        echo 'instancia(++$i) = ' . $instancia->incrementar() . $br;

        echo '</pre>';
        ?>
    </body>
</html>

Espero les sirva el ejemplo, y como dijeran los gringos: "happy conding"

No hay comentarios:

Publicar un comentario

Datos personales

Mi foto
Podrás encontrar códigos recursos y artículos sobre PHP, JavaScript, jQuery, MooTools, Ajax, CSS, HTML, UML, RUP, AUP, XP (eXtreme Programming), Six-Sigma, CMMI, FrameWorks, Zend Framework, Magento, CodeIgniter, CakePHP, Joomla 1.5, Doctrine, Active Record, ORM, POO, MVC, MySql, PostgreSql. Este espacio está destinado a ayudar y compartir un poco de lo mucho que he recibido de la comunidad en la Red.