Нужна помощь в осознании Registry-паттерна (работа с модулями)

zerkms

TDD infected
Команда форума
dark-demon
в случае использования синглтона тебе не приходится заботиться о том что:
1. переменная уже была определена заранее
2. кто-то случайно эту переменную не подменил
 

netstuff

Новичок
Автор оригинала:
...if(!$instance) здесь некорректно, ибо $instance при первом вызове не определен, надо проверять isset.
во-вторых, тебе не кажется, что тут бесконечная рекурсия?
в общем, http://phpfaq.ru/debug тебе поможет :)
ДА. ПОНЯЛ ПОЧЕМУ РЕКУРСИЯ! :D
Мы проверяем свойство $instance, и при этом, если его нет - снова вызываем проверку. Получется рекурсия, так её итить.
Понимаю, что этому свойству надо дать какое-то значение.
Пробовал делать так (по примеру ):
PHP:
		static function __instance() {
			if(!isset($this->instance)) $this->instance = new Singleton();
			else return $this->instance;	
		}
или

PHP:
		static function __instance() {
			if(!isset($this->instance)) {
				$this->instance = true;
				$this->instance = Singleton::__instance();
			}
			else return $this->instance;	
		}
все тоже самое.
итак, как же мне всё-таки определить $instance? :confused:
 

akd

dive now, work later
Команда форума
по примеру? :))
вот твой пример:
PHP:
static function getInstance()
  {
    if (self::$instance == NULL)
    {
      self::$instance = new Logger();
    }
    return self::$instance;
  }
найди отличия в своем коде :)
 

netstuff

Новичок
Так. С Singleton разобрался:

PHP:
	class Singleton {

		static private $instance = NULL;
		
		private function __construct() { }
		private function __clone() {}
		
		public static function __instance() {
			if(is_null(self::$instance)) self::$instance = new Singleton();
			return self::$instance;
		}
		
		public function hello() {
			echo "Hello, World";
		}
		
	}
	$single = Singleton::__instance();
	$single->hello();
Получаю на экранчег:
Но далее история повторяется
PHP:
    class Registry extends Singleton {
    	
    	private $modules;
    	
    	function get($key) {
    		return (isset($this->modules[$key])) ? $this->modules[$key] : false;
		}
		
		function set($key, $object) {
			$this->modules[$key] = $object;	
		}
    	
	}
	
	class Test {
		
		function __construct() {
			Registry::set(get_class($this), $this);
		}
		
		function check() {
			echo "Current registry is: ";
			print_r(Registry::get(get_class($this)));
			echo "<br>";	
		}
			
	}
	
	$test = new Test();
	$test->check();
Current registry is: Test Object ( [modules] => Array ( [Test] => Test Object *RECURSION* ) )
 

netstuff

Новичок
Автор оригинала: fixxxer
upd: опоздал :)
всё-равно спасибо. а что дальше? :rolleyes:

под "что дальше" и имею в виду развитие проблемы описанное двумя постами выше.
рекурсия, почему-то так и осталась. кстати, в процессе размышлений возник вопрос (вы уж простите старика за ламерство):

если мы наследуем класс Singletone, то переменная $instance сохраняет свое значение для всех предков? или у каждого предка своя?

Нижайше кланяюсь в ножки :D
 

fixxxer

К.О.
Партнер клуба
ой, ну а сам ты как думаешь? а если проверить? ну ведь это же быстрее и полезнее, чем ждать пока кто-то ответит, правда же? :)
 

netstuff

Новичок
Автор оригинала: fixxxer
ой, ну а сам ты как думаешь? а если проверить? ну ведь это же быстрее и полезнее, чем ждать пока кто-то ответит, правда же? :)
ну правда не понимаю :(
добавил в класс Registry эту запись
PHP:
	class Singleton {

                ...
		
		public static function __instance() {
			if(is_null(self::$instance)) self::$instance = new Singleton();
			else echo "instance already constructed. ";
			return self::$instance;
		}
		
                ...
		
	}

    class Registry extends Singleton {
    	
    	private $modules;
    	
    	function __construct() {
    		echo get_class($this)." reports: ".get_class(self::__instance())."<br>";	
		}
        ...

    }

	$single = Singleton::__instance();
	$single->hello();
	$reg = new Registry();
получаю ответ

Hello, World
instance already constructed. Registry reports: Singleton
судя по всему, запоминает... :confused:


рекурсия возникает без участия Singleton... хмммммм. ваще :)

-~{}~ 01.06.07 17:52:

Итак, уважаемые коллеги.
Решение проблемы рекурсии я таки нащупал "вслепую".
Поделюсь с Вами затем, чтобы самые честные и добрые из Вас подтвердили мои догадки.

Итак, как это выглядит теперь:

PHP:
    class Registry extends Singleton {
    	
    	private static $modules;
    	
    	static function get($key) {
    		return (isset(self::$modules[$key])) ? self::$modules[$key] : false;
		}
		
		static function set($key, $object) {
			self::$modules[$key] = $object;	
		}
		
		static function check() {
			print_r(self::$modules);	
		}
    	
	}
	
	class Test {
		
		function __construct() {
			Registry::set(get_class($this), $this);
		}
		
		function test() {
			echo "inner calling work successfully!<br>";
		}
		
	}
	
	class innerCallingTest {
	
		function __construct() {
			Registry::set(get_class($this), $this);
		}
		
		function test() {
			echo Registry::get("Test")->test();	
		}
		
	}
И на выходе:
inner calling work successfully!
Array ( [Test] => Test Object ( ) [innerCallingTest] => innerCallingTest Object ( ) )
В какой-то момент времени, я подумал: а как же я пытаюсь обратиться к методу неинициализированного класса Registry? И сделал оба метода статическими. В результате, "лёд тронулся" и пошло говно по трубам".

Честно скажу, что не понимаю, почему возникала рекурсия. По-моему, вместо неё должна была быть ошибка :/

Если кто-то найдет время разъяснить мне мой сегодняшний путь посредством логических умозаключений и граммотных трактовок всем известных понятий - буду очень признателен. Потому как вся проделанная работа была сделана на ощупь и понимания как такового у меня нет.

Спасибо всем за терпение меня =)
 

fixxxer

К.О.
Партнер клуба
воо, молоток :)
насчет рекурсии попозже гляну, если до этого конечно никто не.
 

leadaxe

Новичок
Все просто. Засорять глобальное адресное пространство иногда не хочется.
 

ustas

Элекомист №1
class One
{
private static $fclass;
public $varvar;

private function __construct()
{
// блабла бла
$this->varvar;
}
public static function factory(){
self::$fclass = new One();
return self::$fclass;
}
}

//$class1 = new One(); // не работает

$class2 = One::factory();

почему тут работает только класс2? точно должен понять.
Если из головы выбрасить названия такие как патерн, сиглинтоны фсякие, то понять будет проще.

http://www.php.net/manual/ru/language.oop5.static.php

проблема в обращении из статического метода к несозданому обьекту и еще через $this- то есть текущий объект (сделать невозможное). если бы ты включил error_reporting(E_ALL | E_STRICT);
понял бы быстрее
 

netstuff

Новичок
Автор оригинала: ustas

почему тут работает только класс2? точно должен понять.
Если из головы выбрасить названия такие как патерн, сиглинтоны фсякие, то понять будет проще.

http://www.php.net/manual/ru/language.oop5.static.php

проблема в обращении из статического метода к несозданому обьекту и еще через $this- то есть текущий объект (сделать невозможное). если бы ты включил error_reporting(E_ALL | E_STRICT);
понял бы быстрее
спасибо. теперь отвечу.
во-первых, про обращение к несозданному объекту - это я вроде понял уже ранее. там и написал.
во-вторых, контроль ошибок был включен:

PHP:
ini_set('display_errors',1);
error_reporting(E_ALL);
 

ustas

Элекомист №1
только с описанием, нехер вызывать не то что нуна
 

maxru

МИФИст
PHP:
class core_ModuleSingleton
{
	protected static $instance;
	
	function __construct()
	{
		
	}
	
	function __destruct()
	{
		
		
	}
	
	public static function __instance()
	{
		if(is_null(self::$instance))
		{
			self::$instance = new core_ModuleSingleton();// кстати, можно и self::$instance = new self;
		}
		return self::$instance;
	}
	
	function doit()
	{
		return 'core_ModuleSingleton';
	}
}

class core_ModuleSingletonUrlWrapper extends core_ModuleSingleton
{
	function doit()
	{
		return 'core_ModuleSingletonUrlWrapper';
	}
}
Так вот, как видно из вышеприведенного кода видно, что статический метод класса core_ModuleSingleton возращает экземпляр core_ModuleSingleton, то есть себя самого.
При получении экземпляра core_ModuleSingletonUrlWrapper через метод __instance() я получаю core_ModuleSingleton (что вполне естественно), а мне надо получить core_ModuleSingletonUrlWrapper.
Либо я совсем дурак, либо чего-то недопонял. Как же все-таки получить core_ModuleSingletonUrlWrapper через core_ModuleSingletonUrlWrapper::__instance() ?
 

netstuff

Новичок
Автор оригинала: maxru

Так вот, как видно из вышеприведенного кода видно, что статический метод класса core_ModuleSingleton возращает экземпляр core_ModuleSingleton, то есть себя самого.
При получении экземпляра core_ModuleSingletonUrlWrapper через метод __instance() я получаю core_ModuleSingleton (что вполне естественно), а мне надо получить core_ModuleSingletonUrlWrapper.
Либо я совсем дурак, либо чего-то недопонял. Как же все-таки получить core_ModuleSingletonUrlWrapper через core_ModuleSingletonUrlWrapper::__instance() ?
я это, не долго думая, продемонстрирую как я решил проблему наследования Singltona :) (отдельное спасибо автору поста )

PHP:
		class Singleton {

		   public static function __instance($classname) {
			if(is_null(self::$instance) || get_class(self::$instance) != $classname) self::$instance = new $classname();
			Registry::set(get_class(self::$instance), self::$instance);
			return self::$instance;
		   }
		}

		class Test extends Singleton {
		   
                    function message($msg) {
                        echo $msg;
                    }

		}


		$test = Singleton:__instance("Test");
                $test->test("Всё работает");
 

maxru

МИФИст
Хахаха!
new 'Имя_класса'()
Как же я не догадался. THX!!!

-~{}~ 06.06.07 23:06:

Погоди-ка... а если я белиберду запихну в $test->test('@##@$#@^#@$^#$^#$&%#$&%&') - что получится, а?

-~{}~ 06.06.07 23:07:

То есть так:
$test = Singleton::_instance("!";%:%%?;");
 

netstuff

Новичок
Автор оригинала: maxru
Погоди-ка... а если я белиберду запихну в $test->test('@##@$#@^#@$^#$^#$&%#$&%&') - что получится, а?
Э-э-э-э... белиберда и получицца. test() на то и тест - чтобы не парицца :)

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

maxru

МИФИст
Мне кажется, что как-то криво получается... Хотелось бы покрасивее.
 
Сверху