Singletone + Reflection + PHP 5.3

igortik

Новичок
Покритикуйте реализайцию патерна SIngletone

PHP:
abstract class Singletone
{
	// Хранилище инстанцированных объектов
	private static $_instances = array();
	
	// Приватный конструктоп
	private function __construct(){}
	
	// Запрещаем клонирование
	final private function __clone(){}
	
	// Получение инстанцированного объекта
	public static function getInstance()
    {
		// Имя класса, объект которого создается
		$className = get_called_class();
		
		if(!isset(self::$_instances[$className])){
			// Аргументы, передаваемые конструктору потомка
			$arguments = func_get_args();
			
			// Создание объекта
			try {
				$reflection = new ReflectionClass($className);
				// Создание объекта с передачей параметров конструктору потомка
				// Конструктор должен быть Публичным!
				self::$_instances[$className] = $reflection->newInstanceArgs($arguments);
			}
			catch(ReflectionException $E) {
				// Создание объекта без передачи параметров конструктору потомка
				self::$_instances[$className] = new $className();
			}
		}

        return self::$_instances[$className];
    }
	
	// Уничтожение объекта
	public static function clearInstance($className=NULL)
	{
		if(isset(self::$_instances[$className])){
			unset(self::$_instances[$className]);
			return true;
		}
		return false;
	}
	
	// Замена объекта
	public static function setInstance($className=NULL,$newInstance=NULL)
	{
		if(isset(self::$_instances[$className])){
			self::$_instances[$className] = (object) $newInstance();
			return true;
		}
		return false;
	}
	
	// Вывод информации об объекте
	public static function testInstance($className=NULL)
	{
		if(isset(self::$_instances[$className])){
			var_dump(self::$_instances[$className]);
		}
		return false;
	}
	
	// Массив инстанционированных объектов
	public static function getInstances()
	{
		return self::$_instances;
	}
}
Явные минусы:
1. Надо наследовать
2. Образуется зависимость
3. Конструктор потомка должен быть публичным, если передаем аргументы в getInstance($args)

Плюсы:
1. Вся реализация патерна в одном файле
2. Единое хранилище инстанцированных объектов

Кстати, по поводу п.3. из раздела "Минусы". Когда пробуем отправить аргументы конструктору потомка через Reflection, то, если конструктор этого потомка отличный от публичного, то бросается исключение, т.е. объект создается без передачи аргументов и, к сожалению, никакой ошибки не выводится при попытке дебага данного глюка Reflcetion.

Что думаете?
 

A1x

Новичок
catch(ReflectionException $E) {
я думаю в данном случае отлавливать исключение есть зло так как вот ты передал параметры а объект тихо создался без параметров
т.е. как бы все в порядке когда на самом деле нет

2. если создан экземпляр с одним набором аргументов то получить экземпляр с другими аргументами получается довольно нетривиально
 

tz-lom

Продвинутый новичок
в 5.3 есть ключевое слово static через которое всё это извращение с пулом инстансов можно убить
 

MiksIr

miksir@home:~$
if(!isset(self::$_instances[$className])){ - $className то один и тот же
Я спросил, как вы вообще себе представляете _несколько_экземпляров_ при реализации патерна _синглтон_?
Вот, igortik, считайте это минусом того, что при реализации синглтона вы позволяете передавать какие-то аргументы, чего в принципе хотеть не нужно.
 

tz-lom

Продвинутый новичок
Вот, igortik, считайте это минусом того, что при реализации синглтона вы позволяете передавать какие-то аргументы, чего в принципе хотеть не нужно.
Это реализация паттерна "кто раньше встал того и тапки"
 

igortik

Новичок
tz-lom
Так есть решение п.3. ?
Я читал про static, но было бы неплохо освежить новым линком :)

зы. И что думаете по поводу зависимостей.... (extends), ведь dependency injection здесь не поможет ...
 

igortik

Новичок
MiksIr
т.е. вы считаете, что передавать в getInstance() аргументы это дурной тон?
В какой-то мере я согласен, что пусть getInstance() делает то, что он классически должен, но все же, если есть возможность использовать без казусов передачу аргументов, то это ведь явное расширение возможностей и экономия строк кода, например, для пассивного dependency injection (DI), да и банально для передачи любых данных конструктору потомка ...
 

Lirik

Новичок
igortik
можно ввести метод init() и все, что то вроде
PHP:
  SomeClass::getInstance()->init($someParams);
 

cDLEON

Онанист РНРСlub
Синглтон - это синглтон. Он ни чего не просит.
Вообще я перестал их использовать в ВЕБ. Там, где нужна одна копия объекта - есть ссылка на него, которая попадает туда через конструктор. Большего, по-моему и не нужно.
 

Lirik

Новичок
cDLEON
Можно либо смотреть то куда записываешь, аналогично тому как смотрят инициализирован ли объект синглтона, либо другим способом каким-либо способом(банально через те же isset), или уж завести private поле на крайний случай, в качестве флага, было ли проинициализировано или нет
 

Lirik

Новичок
cDLEON
проще использовать реестр в случае когда нужно инициализировать объект через конструктор и он должен быть только 1. хотя от обращения не через реестр не застраховано
 

cDLEON

Онанист РНРСlub
вопрос не о том, как узнать изнутри. Снаружи.
Не знаю как для вас, а для меня когда, вызываются 2 метода и при смене очередности вызова этих методов, ломается код - попахивает.
 

Lirik

Новичок
cDLEON
если совершать дикие извращения то вот:
PHP:
 if (!SomeClass::getInstance()->isInit())
 SomeClass::getInstance()->init($someParams);
код попахивает всегда и везде, нет идеального кода. это решение надумано лишь тем, что ТС просит сделать то что по правилам делать не надо бы
 

igortik

Новичок
господа, не понимаю о чем вы.
Синглтон решает все те проблемы, о которых вы пишите.

Выполнили getInstance() и понимаете, что получили ссылку на объект, либо только что создали новый.
Реестр в моем примере есть внутри, ничего нового изобретать здесь не нужно, можно писать методы для дебага прям в этом же классе.

Сейчас вопрос более важен на счет передачи параметров, чтобы сделать предложенное мною на всеобщее обозрение решение более актуальным для применения.
 

Lirik

Новичок
igortik
обсуждается инициализация синглотона не через getInstance(), и как узнать был ли он инициализирован(спор не про sefl::$_instance = new self;)
 

cDLEON

Онанист РНРСlub
Lirik
Ну и о чём вы тогда пытаетесь вести дискуссию?

Я веду к тому, что, прежде чем вводить в архитектуру синглтон, 1 000 000 000 000 раз подумайте - а нужно ли? Может быть можно обойтись просто передачей ссылки на этот объект с более низкого уровня?
И тогда желание сделать класс, который бы решал только задачу инициализации синглтона, отпадёт сама собой...
 
Сверху