Pergunta

Se você tivesse uma classe de fábrica que cria novos objetos de algum tipo, e que classe factroy é um singleton, como este:

class Database_Factory extends Base_Factory {
    private static $factory;
    private $objects = array();

    public function __get($profile) {
        // check for object and return it if it's created before
    }

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

O mesmo se repete código qualquer momento onde algum objeto precisa de sua própria fábrica. Então eu decidi fazer esta classe abstrata fábrica e implementar rotinas única específicas para cada fábrica. Mas PHP não permite instanciar a classe abstrata.

abstract class Base_Factory {
    public static function getInstance(){
        if (!self::$factory)
            self::$factory = new self();
        return self::$factory;
    }
}

Erro fatal: Não é possível instanciar abstract class Base_Factory

O que você faria?

Foi útil?

Solução

métodos PHP, self refere-se sempre a classe em que o método é definido. Desde a versão 5.3.0, o PHP suporta “ligação estática tardia”, onde você pode usar a palavra-chave static ao acesso substituído métodos estáticos, bem como a get_called_class() função para obter o nome da classe derivada no contexto estático.

No entanto, seu projeto tem uma grande falha: O $factory propriedade estática definida no Base_Factory é compartilhado entre todas as classes derivadas. Portanto, a primeira vez que um singleton é criado e armazenado nesta propriedade, todas as outras chamadas para getInstance() irá retornar o mesmo objeto, não importa o derivado classe é usada.

Você pode usar um nomes de classe mapeamento dicionário estáticos para objetos únicos:

abstract class Base_Factory {
    private static $_instances = array();
    public static function getInstance() {
        $class = get_called_class();
        if (!isset(self::$_instances[$class])) {
            self::$_instances[$class] = new $class();
        }
        return self::$_instances[$class];
    }
}

Ah, mais uma coisa: o fato de que você está procurando uma possibilidade de reutilização de código para objetos únicos poderia ser uma sugestão para o fato de que você está sobre-usando o padrão de design singleton! Pergunte-se se as classes que você está planejando implementar como singletons são realmente únicos e se não haverá nenhum caso de uso onde você pode querer ter múltiplas instâncias da classe particular.

Muitas vezes, é muito melhor usar apenas um Singleton que representa a corrente “contexto de aplicação” que fornece acessores para objetos que são singletons no que diz respeito a este contexto.

Outras dicas

PHP 5.3 +

abstract class Singleton
{
    /**
     * Instance
     *
     * @var Singleton
     */
    protected static $_instance;

    /**
     * Constructor
     *
     * @return void
     */
    protected function __construct() {}

    /**
     * Get instance
     *
     * @return Singleton
     */
    public final static function getInstance() {
        if (null === static::$_instance) {
            static::$_instance = new static();
        }

        return static::$_instance;
    }
}

PHP> = 5,3 única

abstract class Base_Factory {
    protected static $factory;
    public static function getInstance(){
        if (!self::$factory) {
            $class = get_called_class();
            self::$factory = new $class();
        }
        return self::$factory;
    }
}

Registre seus singletons em uma classe simples como este

class Singletons {
    static private $singleton = array();
    public function getSingleton($class) {
    if (!isset(self::$singleton[$class])) {
        self::$singleton[$class] = new $class;
    }
    return self::$singleton[$class];
    }
}

Em seguida, fazer isso

class aSingleton {
    public $i;
    public function test() {
    ++$this->i;
    echo get_class() . " called {$this->i} times\n";
    }
}

Singletons::getSingleton('aSingleton')->test();
Singletons::getSingleton('aSingleton')->test();

saída

aSingleton called 1 times
aSingleton called 2 times

Por definição classess abstrata não pode ser instanciado em PHP como qualquer outras linguagens orientadas a objeto. Portanto, o seu Base_Factory deve ser interface em vez de classe abstrata.

A partir do manual do PHP: "Não é permitido para criar uma instância de uma classe que tem sido definido como abstrato"

Bem, você poderia fazer uma verificação para garantir que a classe chamando a função não é a Base_Factory.

if(__CLASS__!='Base_Factory')

Em seguida, use $ this em vez de auto para se referir ao objeto atual em vez da classe atual.

if (!$this->factory)
        $this->factory = new self();
    return $this->factory;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top