Singleton и наследование

partizan

Новичок
Singleton и наследование

Нужно в проекте иметь несколько классов со свойством Singleton-a (имеющих единственный экземпляр)

Хотел создать базовый класс Singleton и от него все остальные наследовать
PHP:
class Singleton
{
    private static $instance = null;    
    public static function getInstance ( )
    {
        if ( is_null ( self::$instance ) )
        {
            self::$instance = new Singleton ( );
        }        
        return self::$instance;
    }
}

class NewClass extends Singleton
{
 ...
}

$a = NewClass::getInstance();
но в методе getInstance() будет создаваться экземпляр базового класса Singleton, а не наследника. get_class() и reflection не помогает, т.к. функция статическая.

Есть варианты решения даной проблемы?

Единственное, что смог придумать - в каждом наследнике переопределять переменную, в которой будет храниться имя класса, и это имя использовать в методе getInstance
 

pilot911

Новичок
все дело в Singleton ::$instance - в 5.3 будет отрабатывать так, как ты хочешь, то есть $instance, определенный как

class Singleton
{
private static $instance = null;

будет хранить объект потомка - NewClass, а не базового класса


плюс ошибка - private static $instance = null;


private замени на protected, иначе наследования не произойдет
 

partizan

Новичок
Не понял: откуда там возьмется объект потомка - NewClass, если присваивается ей
self::$instance = new Singleton ( ) ?
 

partizan

Новичок
Автор оригинала: pilot911
self::$instance = new self();
На 5.2.4 получается объкет базово класса, а не потомка. А на последнюю версию ориентироваться не хочется

-~{}~ 15.09.09 05:28:

И с переменной, в которой храниться имя класса тоже не получается:

self::my_class_name тоже дает значение из родителя, а не потомка
 

zerkms

TDD infected
Команда форума
вот вы и убедились, что синглтон не такой и полезный (хороший) паттерн.
юзайте фабрику. м?
 

pilot911

Новичок
зачем тебе имя класса?
делай просто, если не хочешь 5.3

PHP:
class Singleton
{
    protected static $instance = null;    

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

class NewClass extends Singleton
{
    protected static $instance = null;    
}

$a = NewClass::getInstance();
-~{}~ 15.09.09 06:40:

Автор оригинала: zerkms
вот вы и убедились, что синглтон не такой и полезный (хороший) паттерн.
юзайте фабрику. м?
в чем принципиальное отличие ?
 

zerkms

TDD infected
Команда форума
pilot911
может в том, что решатся проблемы тредстартера?

ps:
PHP:
var_dump(get_class($a));
ололо?
 

pilot911

Новичок
Автор оригинала: zerkms
pilot911
может в том, что решатся проблемы тредстартера?
да вряд ли... фабрика создает новые экземпляры объекта при каждом обращении, как я понимаю
 

zerkms

TDD infected
Команда форума
pilot911
что мешает брать и отдавать референсы, вместо создания новых объектов?
 

zerkms

TDD infected
Команда форума
Adelf
основной паттерн там фабрика. а ссылки вполне можно хранить в статическом локальном массиве, без введения лишних реестров.
 

zerkms

TDD infected
Команда форума
pilot911
var_dump(get_class($a));

покажи результат выполнения этой строки в php < 5.3
 

pilot911

Новичок
Автор оригинала: zerkms
pilot911
var_dump(get_class($a));

покажи результат выполнения этой строки в php < 5.3
посмотрел свой код - если в потомке не определить getInstance (а только в базовом классе) - то работать не будет даже несмотря на наличие у потомка

protected static $instances;
 

zerkms

TDD infected
Команда форума
pilot911
мде... возвращаясь к нашим баранам: что насчёт фабрики? :)
 

Major

Новичок
PHP:
<?php

abstract class Singleton
{
    protected static $class_array = array();
    public static $instance;

    public function _construct() { }

    public final function __construct()
    {
           $class = get_class($this);

           if (!in_array($class, array_keys(self::$class_array)))
           {
                      $args = func_get_args();
                      call_user_func_array(array($this, '_construct'), $args);
                      self::$class_array[$class] = $this;
            }
            else
                        trigger_error("Only one instance of the class $class is allowed", E_USER_ERROR);
    }
}


class A extends Singleton
{
           public $foo = 123;

            public function _construct()
            {
                        var_dump($this);
            }
}


$A = new A();
var_dump($A);

new A();
---------------------------------------------------------
PHP:
oxfa@linux-soec:> php test.php
object(A)#1 (1) {
  ["foo"]=>
  int(123)
}
object(A)#1 (1) {
  ["foo"]=>
  int(123)
}

PHP Fatal error:  Only one instance of the class A is allowed in /home/oxfa/test.php on line 21
:confused:
 

Alexandre

PHPПенсионер
а может све же синглетон не предназначен для того, чтоб быть базовым классом? Что нам скажут титаны ООП?
 

Adelf

Administrator
Команда форума
Я не титан, но выскажусь. Когда захотел отнаследовать классы от одного Singleton, то сразу расхотел изза некрасивости реализации. назвал класс Registry и он мне создавал нужных мне одиночек:
PHP:
Registry::get('Cache');
Потом узнал, что этот шаблон так и называется - Registry :)
 

zerkms

TDD infected
Команда форума
Adelf
реестр умеет только хранить данные. сам инстанциировать объекты по имени он не должен. если он создаёт объекты (по факту - становится порождающим паттерном), то он автоматически превращается в фабрику :)
 
Сверху