2010-10-19 9 views
11

Directo al punto: Tengo dos clases singleton, ambas heredan su naturaleza singleton de una superclase. Inicializo algunas propiedades en el primer singleton y luego tengo el segundo singleton que recupera la instancia del primero. Sin embargo, esa instancia no parece ser la que inicié en primer lugar. Un código de ejemplo podría ayudar a explicar esto:Creación de una clase base Singleton en PHP 5.3

En primer lugar, la super-clase, que proporciona la naturaleza Singleton (requiere PHP 5.3 o superior):

class Singleton { 

    protected static $instance; 

    protected function __construct() { } 

    final private function __clone() { } 

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

} 

entonces tenemos la primera Singleton llevar a un valor :

require_once('Singleton.php'); 

class SingletonA extends Singleton { 

    protected $value; 

    public function SingletonA() { 
     $this->value = false; 
    } 

    public function getValue() { 
     return $this->value; 
    } 

    public function setValue($value) { 
     $this->value = $value; 
    } 

} 

A continuación, el segundo producto único que hace referencia a la primera Singleton:

require_once('Singleton.php'); 
require_once('SingletonA.php'); 

class SingletonB extends Singleton { 

    public function getValue() { 
     return SingletonA::getInstance()->getValue(); 
    } 

} 

Ahora para la prueba que muestra cómo esta falla:

require_once('SingletonA.php'); 
require_once('SingletonB.php'); 

SingletonA::getInstance()->setValue(true); 

echo (SingletonA::getInstance()->getValue()) ? "true\n" : "false\n"; 
echo (SingletonB::getInstance()->getValue()) ? "true\n" : "false\n"; 

La prueba se obtiene el siguiente resultado:

true 
false 

Claramente, la instancia SingletonA que las referencias de código de prueba no es la misma instancia que el SingletonB referencias de instancia En resumen, SingletonA no es tan simple como lo necesito. ¿Cómo es esto posible? ¿Y qué magia puedo utilizar para remediar este comportamiento, dándome un singleton verdadero?

+1

Es la primera vez que me encuentro con el comportamiento heredado de Singleton. Si es o no sintácticamente correcto, es bastante extraño. – spender

+0

Un SingletonA nunca será una instancia de SingletonB, a pesar de que ambos son Singletons; la palabra clave 'static' se asegurará de eso. – thetaiko

+0

¿Por qué no usar simplemente un Singleton? – Stephen

Respuesta

11

Intente utilizar isset en lugar de instanceof: OO charla

class Singleton { 
    protected static $instances; 

    protected function __construct() { } 

    final private function __clone() { } 

    public static function getInstance() { 
     $class = get_called_class(); 

     if (!isset(self::$instances[$class])) { 
      self::$instances[$class] = new $class; 
     } 
     return self::$instances[$class]; 
    } 
} 
+0

Gracias un solo día, pero eso me da la misma instancia, que no es lo que quiero. –

+0

@Johan Tienes razón, lo hace. Lo siento por eso. He reescrito tu clase usando una matriz de instancias en 'Singleton :: $ instances', que funciona. – lonesomeday

+0

¡Gracias un millón, hombre! Esta versión incluso se ejecutará en versiones de PHP <5.3, por lo que puedo ver. Pero todavía no entiendo por qué no funcionó. –

0

Estoy bastante seguro de que es porque estás usando métodos estáticos, que no tienen instancias.

0

SingletonA y SingletonB son diferentes clases. Aunque heredan de la misma clase, son clases separadas y tienen diferentes instancias estáticas.

Si cambia el código para obtener 2 instancias de SingletonA o 2 instancias de SingletonB, verá el comportamiento que espera. Pero debido a que son clases diferentes, no son el mismo singleton.

0

de Let. :)

SingletonA y SingletonB son de tipo Singleton

por lo tanto se puede decir:

SingletonAesSingleton

y

SingletonBesSingleton

es decirLos dos son Singleton

El significado esperado de Singleton significa que puede haber sólo una. Mucha gente de un fondo de OO que use su código se confundirá.

Normalmente, la implementación de Singleton sería por clase, ya que la mayoría de los lenguajes de OO no se doblarán para permitir la intención de lo que está proponiendo.

Eso PHP podría hacer (a través de get_called_class() magia) no significa que debería.

Puedo absolutamente aceptar que desde un punto de vista utilitario, la respuesta aceptada se ve bien. Dada la ingenuidad de la respuesta aceptada, propondría un cambio de nombre que no entre en conflicto con la implementación de Singleton "estándar". Desde un punto de vista OO estricto, uno nunca podría heredar de un Singleton, por lo que realmente necesita un nombre diferente.

+0

Gracias por tomarse el tiempo para responder de una manera tan generosa. No reclamaré mucha experiencia en lo que se refiere a la teoría detrás del patrón singleton, pero aunque estoy de acuerdo en que SingletonA y SingletonB pueden decirse que son instancias de Singleton, también son ejemplos de distintos tipos. No he podido encontrar ninguna definición que aborde el aspecto de herencia del patrón, pero la forma en que lo veo es que si una jungla puede contener solo un tigre y un león, ambos pueden coexistir aunque sean ambos felinos.Nuevamente, no reclamo mayor conocimiento de esto que el de mis propios desvaríos. –

+0

Sé lo que quiere decir aquí, y no diseñaría algo con varios singletons de todos modos (usaría uno como máximo, y almacenaría todas las demás instancias en esa). Estoy de acuerdo en que sería mejor (a) cambiar el nombre de la clase base como 'BaseSingleton' o algo similar. – lonesomeday