Pregunta

Digamos que estoy escribiendo una clase PHP (>= 5.0) que debe ser un singleton.Todos los documentos que he leído dicen que se debe hacer que el constructor de la clase sea privado para que no se pueda crear una instancia de la clase directamente.

Entonces si tengo algo como esto:

class SillyDB
{
  private function __construct()
  {

  }

  public static function getConnection()
  {

  }
}

¿Hay algún caso en el que se llame a __construct() aparte de si estoy haciendo un

new SillyDB() 

llamar dentro de la propia clase?

¿Y por qué se me permite crear una instancia de SillyDB desde dentro de sí mismo?

¿Fue útil?

Solución

__construct() solo se llamaría si lo llamara desde un método para la clase que contiene el constructor privado.Entonces, para tu Singleton, es posible que tengas un método como este:

class DBConnection
{
   private static $Connection = null;

   public static function getConnection()
   {
      if(!isset(self::$Connection))
      {
         self::$Connection = new DBConnection();
      }
      return self::$Connection;
   }

   private function __construct()
   {

   }
}

$dbConnection = DBConnection::getConnection();

La razón por la que puede o desearía crear una instancia de la clase desde dentro de sí misma es para poder verificar que solo existe una instancia en un momento dado.Después de todo, este es el objetivo de un Singleton.El uso de un Singleton para una conexión de base de datos garantiza que su aplicación no realice un montón de conexiones de base de datos a la vez.


Editar: Añadido $, según lo sugerido por @emanuele-del-grande

Otros consejos

Aquí hay un singleton muy simple que simplemente genera una cadena de fecha/hora:

class TheDate
{
    private static $DateInstance = null;
    private $dateVal;

    public static function getDateInstance()
    {
        if(!isset(self::$DateInstance))
        {
            self::$DateInstance = new TheDate();
        }

        return self::$DateInstance;
    }

    public static function getDateVal()
    {
        return self::$DateInstance->dateVal;
    }

    private function __construct()
    {
        $this->dateVal = strftime("%Y-%m-%d %H:%M:%S");
    }
}

Hacer algo como esto obviamente me da la misma fecha una y otra vez:

$date1 = TheDate::getDateInstance();
echo $date1->getDateVal() . "<br />";

$date2 = TheDate::getDateInstance();
echo $date2->getDateVal() . "<br />";

Y hacer esto no genera ningún error:

class NewDate extends TheDate
{
    public function __construct()
    {

    }
}

Bien, realicé algunas pruebas por mi cuenta.

  • Si no declara su propio constructor en la subclase, intentar crear una instancia arrojará un error fatal, porque intenta llamar al constructor de la superclase.
  • En el caso de una conexión de base de datos, cuando presumiblemente estás devolviendo (en PHP, de todos modos) una instancia de mysqli o el recurso devuelto por el mysql_connect() función (o algún otro enlace a algún otro RDBMS), siempre que marque la instancia como privada, no hay riesgo de que alguien la subclase y altere el enlace.
  • Como mencioné antes, si alguien realmente quiere anular su comportamiento y hacer múltiples conexiones, también podría hacerlo escribiendo una nueva clase.

Prueba el código, Mark, y cuéntame qué descubres.

EDITAR:Además, en esta situación particular, no estoy seguro de por qué debería preocuparse por evitar que una persona cree subclases.Si alguien tiene acceso a su código PHP para subclasificarlo, entonces también tendrá acceso a su código para copiarlo y cambiar los modificadores de acceso a algo que (por cualquier motivo) considere adecuado.

La utilidad práctica de Singleton en este caso es que, al usarlo, puede asegurarse de utilizar siempre la misma conexión de base de datos para una solicitud HTTP determinada.Lo logra.Las otras cosas (usando final y constructores privados) es útil saberlo desde una perspectiva teórica, y aún más útil saberlo si desea distribuir código con calidad API a otros programadores, pero en el caso de este ejemplo en particular, lo único que hacen las palabras clave es agregar bytes a el tamaño del archivo de su clase.

Un poco de puntillosidad:Para completar, probablemente declarar la clase como final también, ya que no querrías que alguien subclasificara esta clase e implementara su propio constructor público.

(Perdóneme si el compilador detecta la anulación de un constructor privado, pero no creo que sea así)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top