Criando o padrão de design Singleton no PHP5

204

Como alguém criaria uma classe Singleton usando classes PHP5?

Andrew Moore
fonte
1
@ Andrew Não instancia uma segunda instância conectando ao banco de dados então. Passe essa instância para onde for necessário. A necessidade de um Singleton é um cheiro de código. Mais em gooh.posterous.com/singletons-in-php
Gordon
3
@Andrew Mmmmkay. Sem ofensas, mas sugiro que você adquira um livro sobre qualidade de software antes de continuarmos esta discussão. Singletons não simplificam, mas complicam a manutenção e o desenvolvimento normais. De fato, é o contrário: são testes de unidade que simplificam e permitem o desenvolvimento em primeiro lugar.
Gordon
3
@ Andrew: Você assume agora que só precisa de uma conexão com o banco de dados. O que acontece quando seus requisitos mudam e você realmente precisa conversar com 2 servidores de banco de dados? Sem mencionar se você não pode confiar em sua equipe para fazer as coisas corretamente , criar um singleton não ajudará nem um pouco. Faça as coisas desde o início e obtenha uma equipe em que possa confiar e você ficará bem.
precisa saber é o seguinte
4
Só porque o Singleton foi usado em excesso não o torna um padrão ruim que deve ser evitado. Não odeie o Singleton. Às vezes, é uma solução perfeitamente boa para um determinado problema. É melhor começar argumentando por que não devemos usá-lo em vez de apenas emocionalmente degradá-lo.
Gilles Lesire

Respostas:

268
/**
 * Singleton class
 *
 */
final class UserFactory
{
    /**
     * Call this method to get singleton
     *
     * @return UserFactory
     */
    public static function Instance()
    {
        static $inst = null;
        if ($inst === null) {
            $inst = new UserFactory();
        }
        return $inst;
    }

    /**
     * Private ctor so nobody else can instantiate it
     *
     */
    private function __construct()
    {

    }
}

Usar:

$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();

$fact == $fact2;

Mas:

$fact = new UserFactory()

Lança um erro.

Consulte http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static para entender os escopos de variáveis ​​estáticas e por que a configuração static $inst = null;funciona.

Arount
fonte
59
para comparar as duas instâncias, você deve usar === em vez de ==. == retornará true se $ fact1 e $ fact2 forem da mesma classe, mas === somente retornará true se ambos forem da mesma instância do mesmo objeto.
Keith Twombley 15/10/08
10
método clone também deve ser privado
Alex Petrov
22
Esse método não redefinirá a instância do UserFactory para nula sempre que você chamar Instance ()? Em java, a variável $ inst seria um atributo estático privado que não deve ser redefinido repetidamente; caso contrário, você também não poderá torná-lo um singleton.
Rudy Garcia
8
Aqui está uma boa descrição
hereswhatidid
10
Você deve usar $ inst = new self (); não $ inst = new UserFactory (); para quem se deparar com isso mais tarde. +1 para usar uma metodologia PHP integrada.
Ligemer
119

O PHP 5.3 permite a criação de uma classe Singleton herdável via ligação estática tardia:

class Singleton
{
    protected static $instance = null;

    protected function __construct()
    {
        //Thou shalt not construct that which is unconstructable!
    }

    protected function __clone()
    {
        //Me not like clones! Me smash clones!
    }

    public static function getInstance()
    {
        if (!isset(static::$instance)) {
            static::$instance = new static;
        }
        return static::$instance;
    }
}

Isso resolve o problema: antes do PHP 5.3, qualquer classe que estendesse um Singleton produziria uma instância de sua classe pai em vez da sua.

Agora você pode fazer:

class Foobar extends Singleton {};
$foo = Foobar::getInstance();

E $ foo será uma instância do Foobar em vez de uma instância do Singleton.

selfawaresoup
fonte
1
A ligação estática tardia é realmente uma coisa muito boa no php 5.3. Pena que ainda não posso usá-lo.
AntonioCS 21/12/2009
4
De @ggsonic: "subclass should own its own static var. check this: echo get_class(Foobar::getInstance());echo get_class(Singleton::getInstance());".
Brock Adams
4
Isso não funciona, acontece que Foobar foi a primeira classe que você construiu?
22412 Chris KL
1
ainda existe a possibilidade de clonar ..... "$ a = Singleton :: getInstance (); $ b = unserialize (serialize ($ a)); $ a! == $ b;"
bortunac
15
Isso não funciona quando há mais de uma subclasse! $instancereside em Singleton, não na subclasse. Depois que alguma subclasse é instanciada, getInstance () retornará essa instância para todas as subclasses.
Mpartel
116

Infelizmente, a resposta de Inwdr é interrompida quando existem várias subclasses.

Aqui está uma classe base Singleton herdável correta.

class Singleton
{
    private static $instances = array();
    protected function __construct() {}
    protected function __clone() {}
    public function __wakeup()
    {
        throw new Exception("Cannot unserialize singleton");
    }

    public static function getInstance()
    {
        $cls = get_called_class(); // late-static-bound class name
        if (!isset(self::$instances[$cls])) {
            self::$instances[$cls] = new static;
        }
        return self::$instances[$cls];
    }
}

Código do teste:

class Foo extends Singleton {}
class Bar extends Singleton {}

echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";
mpartel
fonte
1
Isso é o mais próximo possível de corrigir a implementação do Singleton. Você também deve considerar usar o método __wakeup () para evitar a desserialização.
Robert Rossmann
Na verdade, você deve lançar uma exceção ou gerar um erro manualmente - declarar a função como protegida / privada somente gerará um E_WARNING dizendo que não pode acessar o método, mas continuaria.
Robert Rossmann 28/10
Obrigado. I normalmente têm todos os avisos etc. transformaram em exceções, então eu esqueci a diferença quando eu testei: P
mpartel
Esta é a única solução que encontrei que lida adequadamente com várias subclasses. Obrigado!
Bob Dankert
36

A maneira real e moderna de fazer o padrão Singleton é:

<?php

/**
 * Singleton Pattern.
 * 
 * Modern implementation.
 */
class Singleton
{
    /**
     * Call this method to get singleton
     */
    public static function instance()
    {
      static $instance = false;
      if( $instance === false )
      {
        // Late static binding (PHP 5.3+)
        $instance = new static();
      }

      return $instance;
    }

    /**
     * Make constructor private, so nobody can call "new Class".
     */
    private function __construct() {}

    /**
     * Make clone magic method private, so nobody can clone instance.
     */
    private function __clone() {}

    /**
     * Make sleep magic method private, so nobody can serialize instance.
     */
    private function __sleep() {}

    /**
     * Make wakeup magic method private, so nobody can unserialize instance.
     */
    private function __wakeup() {}

}

Então agora você pode usá-lo como.

<?php

/**
 * Database.
 *
 * Inherited from Singleton, so it's now got singleton behavior.
 */
class Database extends Singleton {

  protected $label;

  /**
   * Example of that singleton is working correctly.
   */
  public function setLabel($label)
  {
    $this->label = $label;
  }

  public function getLabel()
  {
    return $this->label;
  }

}

// create first instance
$database = Database::instance();
$database->setLabel('Abraham');
echo $database->getLabel() . PHP_EOL;

// now try to create other instance as well
$other_db = Database::instance();
echo $other_db->getLabel() . PHP_EOL; // Abraham

$other_db->setLabel('Priler');
echo $database->getLabel() . PHP_EOL; // Priler
echo $other_db->getLabel() . PHP_EOL; // Priler

Como você vê, essa percepção é muito mais flexível.

Abraham Tugalov
fonte
4
Esta é a resposta mais clara sobre o padrão Singleton neste segmento. Obrigado.
Gus
Eu implementei essa abordagem e ela funciona como esperado: a segunda instância se torna nula. No entanto, eu não precisava estender a classe concreta também. Acabei de implementar o Singleton :: instance () no construtor dessa classe concreta.
snaphuman
na instancefunção não $instancedeve sernullfalse
Mifas 19/05/19
Sim, mas não é função, mas método.
Abraham Tugalov
26

Você provavelmente deve adicionar um método __clone () privado para impedir a clonagem de uma instância.

private function __clone() {}

Se você não incluir esse método, será possível o seguinte

$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;

now $inst1! == $inst2- eles não são mais a mesma instância.

Stefan Gehrig
fonte
11
<?php
/**
 * Singleton patter in php
 **/
trait SingletonTrait {
   protected static $inst = null;

  /**
   * call this method to get instance
   **/
   public static function getInstance(){
      if (static::$inst === null){
         static::$inst = new static();
      }
      return static::$inst;
  }

  /**
   * protected to prevent clonning 
   **/
  protected function __clone(){
  }

  /**
   * protected so no one else can instance it 
   **/
  protected function __construct(){
  }
}

usar:

/**
 *  example of class definitions using SingletonTrait
 */
class DBFactory {
  /**
   * we are adding the trait here 
   **/
   use SingletonTrait;

  /**
   * This class will have a single db connection as an example
   **/
  protected $db;


 /**
  * as an example we will create a PDO connection
  **/
  protected function __construct(){
    $this->db = 
        new PDO('mysql:dbname=foodb;port=3305;host=127.0.0.1','foouser','foopass');
  }
}
class DBFactoryChild extends DBFactory {
  /**
   * we repeating the inst so that it will differentiate it
   * from UserFactory singleton
   **/
   protected static $inst = null;
}


/**
 * example of instanciating the classes
 */
$uf0 = DBFactoryChild::getInstance();
var_dump($uf0);
$uf1 = DBFactory::getInstance();
var_dump($uf1);
echo $uf0 === $uf1;

respose:

object(DBFactoryChild)#1 (0) {
}
object(DBFactory)#2 (0) {
}

Se você estiver usando o PHP 5.4: trait é uma opção, para que você não precise desperdiçar a hierarquia de herança para ter o padrão Singleton

e observe também que, se você usa características ou estende o Singleton classe uma extremidade solta era criar um singleton de classes filho, se você não adicionar a seguinte linha de código:

   protected static $inst = null;

na classe infantil

o resultado inesperado será:

object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}
jose segura
fonte
10
protected  static $_instance;

public static function getInstance()
{
    if(is_null(self::$_instance))
    {
        self::$_instance = new self();
    }
    return self::$_instance;
}

Este código pode ser aplicado a qualquer classe sem se preocupar com o nome da classe.

hungneox
fonte
8

Suporta vários objetos com 1 linha por classe:

Esse método aplicará singletons em qualquer classe que você desejar, basta adicionar 1 método à classe que você deseja criar um singleton e isso fará isso por você.

Isso também armazena objetos em uma classe "SingleTonBase" para que você possa depurar todos os objetos que você usou em seu sistema recorrendo novamente aos SingleTonBaseobjetos.


Crie um arquivo chamado SingletonBase.php e inclua-o na raiz do seu script!

O código é

abstract class SingletonBase
{
    private static $storage = array();

    public static function Singleton($class)
    {
        if(in_array($class,self::$storage))
        {
            return self::$storage[$class];
        }
        return self::$storage[$class] = new $class();
    }
    public static function storage()
    {
       return self::$storage;
    }
}

Então, para qualquer classe que você deseja criar um singleton, basta adicionar este pequeno método único.

public static function Singleton()
{
    return SingletonBase::Singleton(get_class());
}

Aqui está um pequeno exemplo:

include 'libraries/SingletonBase.resource.php';

class Database
{
    //Add that singleton function.
    public static function Singleton()
    {
        return SingletonBase::Singleton(get_class());
    }

    public function run()
    {
        echo 'running...';
    }
}

$Database = Database::Singleton();

$Database->run();

E você pode simplesmente adicionar esta função singleton em qualquer classe que você possui e ela criará apenas 1 instância por classe.

NOTA: Você deve sempre tornar o __construct privado para eliminar o uso da nova Class (); instanciações.

RobertPitt
fonte
5
class Database{

        //variable to hold db connection
        private $db;
        //note we used static variable,beacuse an instance cannot be used to refer this
        public static $instance;

        //note constructor is private so that classcannot be instantiated
        private function __construct(){
          //code connect to database  

         }     

         //to prevent loop hole in PHP so that the class cannot be cloned
        private function __clone() {}

        //used static function so that, this can be called from other classes
        public static function getInstance(){

            if( !(self::$instance instanceof self) ){
                self::$instance = new self();           
            }
             return self::$instance;
        }


        public function query($sql){
            //code to run the query
        }

    }


Access the method getInstance using
$db = Singleton::getInstance();
$db->query();
rizon
fonte
5

Você realmente não precisa usar o padrão Singleton porque é considerado um antipadrão. Basicamente, existem muitas razões para não implementar esse padrão. Leia isto para começar: Prática recomendada em classes singleton PHP .

Se, afinal, você ainda acha que precisa usar o padrão Singleton, poderíamos escrever uma classe que nos permita obter a funcionalidade Singleton estendendo nossa classe abstrata SingletonClassVendor.

Foi com isso que eu vim para resolver esse problema.

<?php
namespace wl;


/**
 * @author DevWL
 * @dosc allows only one instance for each extending class.
 * it acts a litle bit as registry from the SingletonClassVendor abstract class point of view
 * but it provides a valid singleton behaviour for its children classes
 * Be aware, the singleton pattern is consider to be an anti-pattern
 * mostly because it can be hard to debug and it comes with some limitations.
 * In most cases you do not need to use singleton pattern
 * so take a longer moment to think about it before you use it.
 */
abstract class SingletonClassVendor
{
    /**
     *  holds an single instance of the child class
     *
     *  @var array of objects
     */
    protected static $instance = [];

    /**
     *  @desc provides a single slot to hold an instance interchanble between all child classes.
     *  @return object
     */
    public static final function getInstance(){
        $class = get_called_class(); // or get_class(new static());
        if(!isset(self::$instance[$class]) || !self::$instance[$class] instanceof $class){
            self::$instance[$class] = new static(); // create and instance of child class which extends Singleton super class
            echo "new ". $class . PHP_EOL; // remove this line after testing
            return  self::$instance[$class]; // remove this line after testing
        }
        echo "old ". $class . PHP_EOL; // remove this line after testing
        return static::$instance[$class];
    }

    /**
     * Make constructor abstract to force protected implementation of the __constructor() method, so that nobody can call directly "new Class()".
     */
    abstract protected function __construct();

    /**
     * Make clone magic method private, so nobody can clone instance.
     */
    private function __clone() {}

    /**
     * Make sleep magic method private, so nobody can serialize instance.
     */
    private function __sleep() {}

    /**
     * Make wakeup magic method private, so nobody can unserialize instance.
     */
    private function __wakeup() {}

}

Use exemplo:

/**
 * EXAMPLE
 */

/**
 *  @example 1 - Database class by extending SingletonClassVendor abstract class becomes fully functional singleton
 *  __constructor must be set to protected becaouse: 
 *   1 to allow instansiation from parent class 
 *   2 to prevent direct instanciation of object with "new" keword.
 *   3 to meet requierments of SingletonClassVendor abstract class
 */
class Database extends SingletonClassVendor
{
    public $type = "SomeClass";
    protected function __construct(){
        echo "DDDDDDDDD". PHP_EOL; // remove this line after testing
    }
}


/**
 *  @example 2 - Config ...
 */
class Config extends SingletonClassVendor
{
    public $name = "Config";
    protected function __construct(){
        echo "CCCCCCCCCC" . PHP_EOL; // remove this line after testing
    }
}

Apenas para provar que funciona como esperado:

/**
 *  TESTING
 */
$bd1 = Database::getInstance(); // new
$bd2 = Database::getInstance(); // old
$bd3 = Config::getInstance(); // new
$bd4 = Config::getInstance(); // old
$bd5 = Config::getInstance(); // old
$bd6 = Database::getInstance(); // old
$bd7 = Database::getInstance(); // old
$bd8 = Config::getInstance(); // old

echo PHP_EOL."COMPARE ALL DATABASE INSTANCES".PHP_EOL;
var_dump($bd1);
echo '$bd1 === $bd2' . ($bd1 === $bd2)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd2 === $bd6' . ($bd2 === $bd6)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd6 === $bd7' . ($bd6 === $bd7)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE

echo PHP_EOL;

echo PHP_EOL."COMPARE ALL CONFIG INSTANCES". PHP_EOL;
var_dump($bd3);
echo '$bd3 === $bd4' . ($bd3 === $bd4)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd4 === $bd5' . ($bd4 === $bd5)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd5 === $bd8' . ($bd5 === $bd8)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
DevWL
fonte
Ao ler respostas mais votadas, eu tinha algo em mente. Felizmente, foi já aqui :)
hatef
3

Toda essa complexidade ("ligação estática tardia" ... harumph) é, para mim, simplesmente um sinal do modelo de objeto / classe quebrado do PHP. Se os objetos de classe fossem objetos de primeira classe (consulte Python), "$ _instance" seria uma instância de classe variável de - um membro do objeto de classe, em oposição a um membro / propriedade de suas instâncias, e também em oposição a compartilhado por seus descendentes. No mundo do Smalltalk, essa é a diferença entre uma "variável de classe" e uma "variável de instância de classe".

No PHP, parece-me que precisamos levar a sério a orientação de que os padrões são um guia para escrever código - talvez pensemos em um modelo Singleton, mas tentando escrever código que herda de uma classe "Singleton" real parece mal orientado para o PHP (embora eu suponha que uma alma empreendedora possa criar uma palavra-chave SVN adequada).

Continuarei a codificar cada singleton separadamente, usando um modelo compartilhado.

Observe que eu estou absolutamente fora da discussão sobre singletons-are-evil, a vida é muito curta.

Tom Stambaugh
fonte
Suas observações estão certas ao visualizar a crescente complexidade da linguagem PHP. Parece que muitas novas palavras-chave estão sendo adicionadas para resolver nossos buracos de design diferentes em muitos paradigmas de codificação diferentes. Pior ainda, devido à alta taxa de alterações e à distorção de versão entre hosts e plataformas de desenvolvimento, a "solução do dia" de hoje (como características na resposta de @Eric Anderson [ stackoverflow.com/a/23998306/3696363] ) não funciona em sistemas de produção que podem estar executando uma versão "estável" em vez da "melhor, mais recente".
Eliyahu Skoczylas 6/03/16
2

Sei que isso provavelmente causará uma guerra de chamas desnecessária, mas posso ver como você pode querer mais de uma conexão com o banco de dados, por isso admito que o singleton pode não ser a melhor solução para isso ... no entanto, existem outros usos do padrão singleton que considero extremamente úteis.

Aqui está um exemplo: eu decidi rodar meu próprio MVC e mecanismo de modelagem porque queria algo realmente leve. No entanto, os dados que eu quero exibir contêm muitos caracteres matemáticos especiais, como ≥ e μ, e o que você tem ... Os dados são armazenados como o caractere UTF-8 real no meu banco de dados, em vez de pré-codificado em HTML, porque meu aplicativo pode fornecer outros formatos, como PDF e CSV, além do HTML. O local apropriado para formatar para HTML está dentro do modelo ("visualização", se desejar), responsável por renderizar a seção da página (snippet). Eu quero convertê-los em suas entidades HTML apropriadas, mas a função get_html_translation_table () do PHP não é super rápida. Faz mais sentido recuperar os dados uma vez e armazenar como uma matriz, disponibilizando-os para uso de todos. Aqui' uma amostra bati juntos para testar a velocidade. Presumivelmente, isso funcionaria independentemente de os outros métodos que você usar (depois de obter a instância) serem estáticos ou não.

class EncodeHTMLEntities {

    private static $instance = null;//stores the instance of self
    private $r = null;//array of chars elligalbe for replacement

    private function __clone(){
    }//disable cloning, no reason to clone

    private function __construct()
    {
        $allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
        $specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
        $this->r = array_diff($allEntities, $specialEntities);
    }

    public static function replace($string)
    {
        if(!(self::$instance instanceof self) ){
            self::$instance = new self();
        }
        return strtr($string, self::$instance->r);
    }
}
//test one million encodings of a string
$start = microtime(true);
for($x=0; $x<1000000; $x++){
    $dump = EncodeHTMLEntities::replace("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)");
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds using singleton\n";
//now repeat the same without using singleton
$start = microtime(true);
for($x=0; $x<1000000; $x++){
    $allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
    $specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
    $r = array_diff($allEntities, $specialEntities);
    $dump = strtr("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)", $r);
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds without using singleton";

Basicamente, vi resultados típicos como este:

php test.php
Tempo de execução: 27,842966794968 segundos usando singleton
Tempo de execução: 237.78191494942 segundos sem usar o singleton

Portanto, embora eu certamente não seja especialista, não vejo uma maneira mais conveniente e confiável de reduzir a sobrecarga de chamadas lentas para algum tipo de dados, ao mesmo tempo em que é super simples (linha de código única para fazer o que você precisa). Meu exemplo tem apenas um método útil e, portanto, não é melhor do que uma função definida globalmente, mas assim que você tiver dois métodos, você desejará agrupá-los, certo? Estou longe da base?

Além disso, prefiro exemplos que realmente fazem alguma coisa, pois às vezes é difícil visualizar quando um exemplo inclui instruções como "// faça algo útil aqui", que vejo o tempo todo ao procurar por tutoriais.

De qualquer forma, eu adoraria comentários ou comentários sobre por que usar um singleton para esse tipo de coisa é prejudicial (ou excessivamente complicado).

user2009125
fonte
1

Este artigo aborda o tópico amplamente: http://www.phptherightway.com/pages/Design-Patterns.html#singleton

Observe o seguinte:

  • O construtor __construct()é declarado protectedpara impedir a criação de uma nova instância fora da classe através do newoperador.
  • O método mágico __clone()é declarado privatepara impedir a clonagem de uma instância da classe através do cloneoperador.
  • O método mágico __wakeup()é declarado privatepara impedir a desserialização de uma instância da classe através da função global unserialize().
  • Uma nova instância é criada através de ligação tardia no método de criação estática estática getInstance()com a palavra chave static. Isso permite a subclasse de class Singletonno exemplo.
Krzysztof Przygoda
fonte
1

Eu escrevi há muito tempo pensado para compartilhar aqui

class SingletonDesignPattern {

    //just for demo there will be only one instance
    private static $instanceCount =0;

    //create the private instance variable
    private static $myInstance=null;

    //make constructor private so no one create object using new Keyword
    private function  __construct(){}

    //no one clone the object
    private function  __clone(){}

    //avoid serialazation
    public function __wakeup(){}

    //ony one way to create  object
    public static  function  getInstance(){

        if(self::$myInstance==null){
            self::$myInstance=new SingletonDesignPattern();
            self::$instanceCount++;
        }
        return self::$myInstance;
    }

    public static function getInstanceCount(){
        return self::$instanceCount;
    }

}

//now lets play with singleton design pattern

$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();

echo "number of instances: ".SingletonDesignPattern::getInstanceCount();
Gyaneshwar Pardhi
fonte
0

Concordo com a primeira resposta, mas também declararia a classe como final, para que não possa ser estendida, pois estender um singleton viola o padrão de singleton. Além disso, a variável de instância deve ser privada para que não possa ser acessada diretamente. Também torne o método __clone privado, para que você não possa clonar o objeto singleton.

Abaixo está um código de exemplo.

/**
 * Singleton class
 *
 */
final class UserFactory
{
    private static $_instance = null;

    /**
     * Private constructor
     *
     */
    private function __construct() {}

    /**
     * Private clone method
     *
     */
     private function __clone() {}

    /**
     * Call this method to get singleton
     *
     * @return UserFactory
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new UserFactory();
        }
        return self::$_instance;
    }
}

Exemplo de uso

$user_factory = UserFactory::getInstance();

O que isso impede você de fazer (o que violaria o padrão singleton ..

VOCÊ NÃO PODE FAZER ISSO!

$user_factory = UserFactory::$_instance;

class SecondUserFactory extends UserFactory { }
Joseph Crawford
fonte
0

Esse deve ser o caminho certo de Singleton.

class Singleton {

    private static $instance;
    private $count = 0;

    protected function __construct(){

    }

    public static function singleton(){

        if (!isset(self::$instance)) {

            self::$instance = new Singleton;

        }

        return self::$instance;

    }

    public function increment()
    {
        return $this->count++;
    }

    protected function __clone(){

    }

    protected function __wakeup(){

    }

} 
Mário Kapusta
fonte
0

Eu gostei do método @ jose-segura de usar características, mas não gostei da necessidade de definir uma variável estática nas subclasses. Abaixo está uma solução que a evita armazenando em cache as instâncias em uma variável local estática no método de fábrica indexado pelo nome da classe:

<?php
trait Singleton {

  # Single point of entry for creating a new instance. For a given
  # class always returns the same instance.
  public static function instance(){
    static $instances = array();
    $class = get_called_class();
    if( !isset($instances[$class]) ) $instances[$class] = new $class();
    return $instances[$class];
  }

  # Kill traditional methods of creating new instances
  protected function __clone() {}
  protected function __construct() {}
}

O uso é o mesmo que @ jose-segura, apenas não é necessária a variável estática nas subclasses.

Eric Anderson
fonte
0

Classe de banco de dados que verifica se existe alguma instância de banco de dados existente, ela retornará a instância anterior.

   class Database {  
        public static $instance;  
         public static function getInstance(){  
            if(!isset(Database::$instance) ) {  
                Database::$instance = new Database();  
            }  
           return Database::$instance;  
         }  
         private function __cunstruct() {  
           /* private and cant create multiple objects */  
         }  
         public function getQuery(){  
            return "Test Query Data";  
         }  
    }  
    $dbObj = Database::getInstance();  
    $dbObj2 = Database::getInstance();  
    var_dump($dbObj);  
    var_dump($dbObj2);  


/* 
After execution you will get following output: 

object(Database)[1] 
object(Database)[1] 

*/  

Ref http://www.phptechi.com/php-singleton-design-patterns-example.html

sunil rajput
fonte
0

Este é o exemplo de create singleton na classe Database

padrões de design 1) singleton

class Database{
  public static $instance;
  public static function getInstance(){
    if(!isset(Database::$instance)){
    Database::$instance=new Database();

     return Database::$instance;
    }

  }

  $db=Database::getInstance();
  $db2=Database::getInstance();
  $db3=Database::getInstance();

  var_dump($db);
  var_dump($db2);
  var_dump($db3);

então colocar fora é -

  object(Database)[1]
  object(Database)[1]
  object(Database)[1]

use apenas uma instância única e não crie 3 instâncias

Surendra Kumar Ahir
fonte
0

Exemplo rápido:

final class Singleton
{
    private static $instance = null;

    private function __construct(){}

    private function __clone(){}

    private function __wakeup(){}

    public static function get_instance()
    {
        if ( static::$instance === null ) {
            static::$instance = new static();
        }
        return static::$instance;
    }
}

Espero ajuda.

Dmitry
fonte
-4

Aqui está o meu exemplo que fornece a capacidade de chamar como $ var = new Singleton () e também criar 3 variáveis ​​para testar se ele cria um novo objeto:

class Singleton{

    private static $data;

    function __construct(){
        if ($this::$data == null){
            $this->makeSingleton();
        }
        echo "<br/>".$this::$data;
    }

    private function makeSingleton(){
        $this::$data = rand(0, 100);
    }

    public function change($new_val){
        $this::$data = $new_val;
    }

    public function printme(){
        echo "<br/>".$this::$data;
    }

}


$a = new Singleton();
$b = new Singleton();
$c = new Singleton();

$a->change(-2);
$a->printme();
$b->printme();

$d = new Singleton();
$d->printme();
bboydev
fonte
5
Exceto que não é um singleton. Você pode criar várias instâncias da classe Singleton.
Andrew Moore
Eu acho que é, afinal, porque não importa qual instância afeta a classe Singleton, as alterações são para todas as instâncias do Singleton. Eu adicionei mais duas funções acima. Agora, vamos tentar modificar dados em uma instância e verificar as outras. Então, não é Singleton e se não - o que está incorreto?
bboydev
5
Um singleton é uma classe que permite apenas uma instância de si mesma. Ao criar várias instâncias, você está anulando esse princípio.
Andrew Moore