Php orientado a objetos, parte 13: Singleton

16 Ene

Ok, hace ya casi tres años o más, inicié esta serie de publicaciones de PHP, y lo he terminado hace bastante tiempo también, sin embargo retomo con una publicación más, con una duda que me compartió un chico hace unos meses.

Todo partía desde el inicio de una conexión a la base de datos, ¿qué pasa cuando debemos hacer varias consultas, y necesitamos un objeto conexión, pero uno solo que podamos reutilizar, sin necesidad de crear nuevas instancias?

Para lograr esta solución debemos recurrir a un patrón muy común en los lenguajes que manejan objetos: singleton.

¿Pero qué es esto? Bueno, básicamente un singleton, es una clase que sólo tendrá una única instancia. Para ello, entonces lo primero es crear privado el constructor:

class MiSingleton {
   private function __construct(){
      //
   }
}

Aquí si intentamos crear una instancia de dicha clase nos devolverá un Fatal error.

Sin embargo, esto no tiene mucha utilidad, ya que no tendremos más de una instancia, pero tampoco tendremos una sola, para eso debemos crear un método que va a verificar si ya hay una instancia creada, de haberlo nos devolverá ese único objeto y de lo contrario, creará una.

La clase quedaría:

class MiSingleton {
   private static $instancia = null;
   private function __construct(){
      //
   }
   public static function getInstancia(){
      if(!self::$instancia){
         self::$instancia = new self();
      }
      return self::$instancia;
   }
 }

Y para crear una instancia de este objeto:

$instancia = MiSingleton::getInstancia();

Podemos probar si esto es así, que se crea una sólo instancia y realizamos la siguiente prueba:

class MiSingleton {
   private static $instancia = null;
   private function __construct(){
      //
   }
   public static function getInstancia(){
      if(!self::$instancia){
         echo 'No existe una instancia, así que la creamos. <br />';
         self::$instancia = new self();
      }else{
         echo 'Ya hay una instancia creada. <br />';
      }
      return self::$instancia;
   }
 }

Y a continuación:

$instancia = MiSingleton::getInstancia();
$instancia = MiSingleton::getInstancia();
$instancia = MiSingleton::getInstancia();

La primera vez que llamamos al método getInstancia(), como no existe un objeto creado, entonces se creará uno nuevo, y la segunda y tercera nos devolverá el objeto creado en la primera.

Bien, ahora que ya sabemos cómo funciona una clase singleton, podemos retomar el tema con el que iniciamos. Cuando vamos a usar una base de datos, podemos tener una sólo instancia, no es necesario, como hicimos en las publicaciones pasadas, crear una nueva cada vez que generamos una nueva instancia. Por tanto podemos modificar la clase Conexión de la siguiente manera:

<?php
if (!defined('CONTROLADOR'))
   exit;
class Conexion {
   private $tipo_de_base = 'mysql';
   private $host = 'localhost';
   private $nombre_de_base = 'batman';
   private $usuario = 'root';
   private $contrasena = '';
   private static $instancia = null;
   private function __construct() {
      try {
         self::$instancia = new PDO($this->tipo_de_base . ':host=' . $this->host . ';dbname=' . $this->nombre_de_base, $this->usuario, $this->contrasena);
      } catch (PDOException $e) {
         echo 'Ha surgido un error y no se puede conectar a la base de datos. Detalle: ' . $e->getMessage();
         exit;
      }
   }
   public static function getInstancia(){
      if(!self::$instancia){
         new self();
      }
      return self::$instancia;
   }
   public static function cerrar(){
      self::$instancia = null;
   }
}

Además de agregar el método getInstancia(), también agregamos uno llamado cerrar(), que dejará en null esa instancia única, en criollo, va a cerrar la base de datos.

A continuación dejo el ejemplo completo:

Descargar ejemplo

Anterior: Php orientado a objetos, parte 12: PDO, Buscar registros en una base de datos

Redes sociables

    6 thoughts on “Php orientado a objetos, parte 13: Singleton

    1. Sensacional !!! ajjajajaja…

      Como loco buscando como hacer esto… (Trabajo) Hasta ahora tengo todo a lo bruto … Y estoy “clasificando” los desarrollos, para ver si en un tiempo, puedo tenerlo bien organizado para minificar tiempos de desarrollo … Muchas gracias un trabajo impresionante y util !!!

      Abuso de tu sabiduria … En mi caso tengo tres bases de datos… Claro con logins diferentes… Como seria la mejor manera… Tener tres conexiones diferentes en el fichero Conexion.php o se te ocurre hacerlo de alguna otra manera… En algunas paginas me tengo que conectar a varias de estas BD para obtener datos y luego insertarlos en la tercera.. Un **** lio.. Ya me gustaria tener solo una, pero no puedo….
      La otra solucion que tengo en mente es cerrar la conexion y crear una nueva y listo…

      Gracias de antemano makinon !!!

    2. Buenos días, primero te queria agradecer por el tutorial, me esta ayudando muchisimo con un trabajo de la facu, bueno con eso mismo tengo un problema, la idea basicamente es mostrar una serie de alumnos ingresan su apellido o parte de el, osea un select %like%, el tema es que no lo puedo hacer andar, no me devuelve nada, el código que estoy usando es este, esto esta en mi clase alumnos, y la parte de mostrarlo y ingresar el apellido en otra vista

      public static function buscarPorApellidos($apellidos){
      $conexion = new Conexion();
      $consulta = $conexion->prepare(‘SELECT id, nombres, apellidos, dni, anio, division, tutornombres, tutorapellidos, email, tel, telemergencia FROM alummnos WHERE apellidos = :apellidos’);
      $apellidos = “%$apellidos%”;
      $consulta->bindParam(‘:apellidos’, $apellidos);
      $consulta->execute();
      $registros = $consulta->fetch();
      $conexion = null;
      return $registros;

      Todo eso mas la parte de mostrarlo en una tabla y el formulario donde obtengo el apellido
      Te agradecería mucho si me pudieras pasar un ejemplo de algo similar o si estas disponible te podría pasar todo lo que tengo así me decís donde me equivoco, desde ya muchas gracias, te felicito por la pagina. Julian.

      • si vas a usar like, están bien los comodines (%), pero deberías usar LIKE en lugar de =

        select columna, from tabla where columna like ‘%cadena%’

        Saludos!

    Deja un comentario

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *


    *