Pergunta

Digamos que eu esteja escrevendo uma classe PHP (>= 5.0) que pretende ser um singleton.Todos os documentos que li dizem para tornar o construtor da classe privado para que a classe não possa ser instanciada diretamente.

Então, se eu tiver algo assim:

class SillyDB
{
  private function __construct()
  {

  }

  public static function getConnection()
  {

  }
}

Há algum caso em que __construct() é chamado diferente de se eu estiver fazendo um

new SillyDB() 

chamar dentro da própria classe?

E por que posso instanciar o SillyDB de dentro dele?

Foi útil?

Solução

__construct() só seria chamado se você o chamasse de dentro de um método para a classe que contém o construtor privado.Então, para o seu Singleton, você pode ter um 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();

A razão pela qual você pode/gostaria de instanciar a classe de dentro dela é para que você possa verificar se existe apenas uma instância em um determinado momento.Afinal, esse é o objetivo de um Singleton.Usar um Singleton para uma conexão de banco de dados garante que seu aplicativo não faça muitas conexões de banco de dados ao mesmo tempo.


Editar: Adicionado $, conforme sugerido por @emanuele-del-grande

Outras dicas

Aqui está um singleton muito simples que apenas gera uma string de data/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");
    }
}

Fazer algo assim obviamente me dá a mesma data repetidamente:

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

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

E fazer isso não gera nenhum erro:

class NewDate extends TheDate
{
    public function __construct()
    {

    }
}

OK, fiz alguns testes por conta própria.

  • Se você não declarar seu próprio construtor na subclasse, tentar instanciá-lo gerará um erro fatal, pois ele tenta chamar o construtor da superclasse.
  • No caso de uma conexão de banco de dados, quando você provavelmente está retornando (em PHP, pelo menos) uma instância mysqli ou o recurso retornado pelo mysql_connect() função (ou algum outro link para algum outro RDBMS), contanto que você marque a instância como privada, não há ameaça de alguém subclassificá-la e adulterar o link.
  • Como mencionei antes, se alguém realmente quiser substituir seu comportamento e fazer múltiplas conexões, poderia muito bem fazê-lo escrevendo uma nova classe.

Teste o código, Mark, e me conte o que você descobriu.

EDITAR:Além disso, nesta situação específica, não sei por que você precisaria se preocupar em impedir que uma pessoa subclasse.Se alguém tiver acesso ao seu código PHP para subclassificá-lo, também terá acesso ao seu código para copiá-lo e alterar os modificadores de acesso para algo que (por qualquer motivo) considere adequado.

A utilidade prática do Singleton neste caso é que, ao usá-lo, você pode garantir que estará sempre usando a mesma conexão de banco de dados para uma determinada solicitação HTTP.Isso é feito.As outras coisas (usando final e construtores privados) é útil saber do ponto de vista teórico, e ainda mais útil saber se você deseja distribuir código com qualidade de API para outros programadores, mas no caso deste exemplo específico, tudo o que as palavras-chave estão fazendo é adicionar bytes a o tamanho do seu arquivo de classe.

Uma pequena escolha:Para completar, você provavelmente declarar a classe como final também, já que você não gostaria que alguém subclassificasse essa classe e implementasse seu próprio construtor público.

(Perdoe-me se o compilador detectar a substituição de um construtor privado, mas acho que não)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top