php - myclabs - Extender la clase de singleton abstracta
php laravel enum (6)
Si tuvieras una clase de fábrica que crea nuevos objetos de algún tipo, y esa clase de factroy es un singleton, así:
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;
}
}
El mismo código se repite en cualquier momento donde un objeto necesita su propia fábrica. Así que decidí hacer un resumen de esta clase de fábrica e implementar rutinas específicas para cada fábrica. Pero PHP no permite instanciar la clase abstracta.
abstract class Base_Factory {
public static function getInstance(){
if (!self::$factory)
self::$factory = new self();
return self::$factory;
}
}
Error grave: no se puede crear una instancia de la clase abstracta Base_Factory
¿Qué harías?
Bueno, podrías hacer una verificación para asegurarte de que la clase que llama a la función no es la Base_Factory.
if(__CLASS__!=''Base_Factory'')
Luego use $ this en lugar de self para referirse al objeto actual en lugar de a la clase actual.
if (!$this->factory)
$this->factory = new self();
return $this->factory;
En los métodos PHP, self
siempre se refiere a la clase donde se define el método. Desde la versión 5.3.0, PHP admite el "enlace estático tardío", donde puede usar la palabra clave static
para acceder a métodos estáticos anulados, así como la función get_called_class()
para obtener el nombre de la clase derivada en un contexto estático.
Sin embargo, su diseño tiene un defecto importante: la propiedad estática $factory
definida en Base_Factory
se comparte en todas las clases derivadas. Por lo tanto, la primera vez que se crea un singleton y se almacena en esta propiedad, todas las demás llamadas a getInstance()
devolverán el mismo objeto, sin importar qué clase derivada se use.
Podría usar un diccionario estático asignando nombres de clase a objetos singleton:
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];
}
}
Oh, una cosa más: ¡El hecho de que estés buscando la posibilidad de reutilizar el código para objetos singleton podría ser una señal de que estás usando demasiado el patrón de diseño de singleton! Pregúntese si las clases que planea implementar como singletons realmente son singletons y si no habrá ningún caso de uso en el que desee tener varias instancias de la clase en particular.
A menudo es mucho mejor usar solo un singleton que represente el "contexto de aplicación" actual que proporciona accesores para los objetos que son singletons con respecto a este contexto.
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 solamente
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;
}
}
Por definición, las clases abstractas no se pueden crear instancias en PHP como cualquier otro lenguaje orientado a objetos. Así que su Base_Factory debería ser una interfaz en lugar de una clase abstracta.
Del manual de PHP: "No está permitido crear una instancia de una clase que se haya definido como abstracta".
Registra tus singletons en una clase simple como esta
class Singletons {
static private $singleton = array();
public function getSingleton($class) {
if (!isset(self::$singleton[$class])) {
self::$singleton[$class] = new $class;
}
return self::$singleton[$class];
}
}
Entonces haz esto
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();
Salida
aSingleton called 1 times
aSingleton called 2 times