Page 1 of 1

Singleton and Registry Help

Posted: Fri Feb 03, 2006 6:28 pm
by John Cartwright
Okay.. I've been using registry for awhile but I recently noticed that my singleton was not acting like a singleton at all.. there is obviously something I am missing.. but I cannot find much helpful documentation on this.. :\

Heres the code I'm using

Code: Select all

class Registry 
	{
		 var $_cache_stack;
	
		 function Registry() {
			  $this->_cache_stack = array(array());
		 }
		 
		 function setEntry($key, &$item) {
			  $this->_cache_stack[0][$key] = &$item;
		 }
		 
		 function &getEntry($key) {
			  return $this->_cache_stack[0][$key];
		 }
		
		 function isEntry($key) {
			  return ($this->getEntry($key) !== null);
		 }
		 
		 function &instance() {
			  static $registry = false;
			  if (!$registry) {
					$registry = new Registry();
			  }
			  return $registry;
		 }
		 
		 function save() {
			  array_unshift($this->_cache_stack, array());
			  if (!count($this->_cache_stack)) {
					trigger_error('Registry lost');
			  }
		 }
		 
		 function restore() {
			  array_shift($this->_cache_stack);
		 }
	}

	class Singleton 
	{
		 function Singleton() {
			  $registry = &Registry::instance();
			  if ($registry->isEntry('singleton ' . get_class($this))) {
					trigger_error(
							  'Already an instance of singleton ' .
							  get_class($this));
			  }
			  
			  echo 'testing';
		 }
		 
		 function &instance($class) {
			  $registry = &Registry::instance();
			  if (!$registry->isEntry('singleton ' . $class)) {
					$registry->setEntry(
							  'singleton ' . $class, new $class());
			  }
			  return $registry->getEntry('singleton ' . $class);
		 }
	}
Anways, I did a quick test to see if the instance was being saved, which is wasn't

Code: Select all

class testRegistry 
	{
		var $_input;
	}

        $testReg = Singleton::instance('testRegistry');
	$testReg->_input = 'snap1';
	
	$testReg = Singleton::instance('testRegistry');
	print_r($testReg);	#failed
	$testReg->_input = 'snap2';
	print_r($testReg);	#ok
	
	class testRegMethod 
	{
		function testRegMethod() {
			$testReg = Singleton::instance('testRegistry');
			print_r($testReg); #failed
			$testReg->_input = 'snap3';
			print_r($testReg); #ok
			
		}
	}
	
	$testRegMethod = new testRegMethod();
	$testReg = Singleton::instance('testRegistry');	
	print_r($testReg); #failed
outputs

Code: Select all

testregistry Object
(
    [_input] => 
)
testregistry Object
(
    [_input] => snap2
)
testregistry Object
(
    [_input] => 
)
testregistry Object
(
    [_input] => snap3
)
testregistry Object
(
    [_input] => 
)
Somethings that I realized is, when does the singleton's constructor get called, since I only should be calling this class statically, correct?
When and where do the methods $registry->save() and $registry->restore() actually get called?

Posted: Fri Feb 03, 2006 7:29 pm
by Christopher
If you are using PHP4 (which cannot store references in statics) I believe it needs to be:

Code: Select all

function &instance() {
              static $registry = array();
              if (! $registry) {
                    $registry[0] = & new Registry(); 
              }
              return $registry[0];
         }
In PHP5 you can just create a static class property (rather than function local var) which simpifies things.

Posted: Fri Feb 03, 2006 7:52 pm
by John Cartwright
I've tried that.. but to the same effect.

Posted: Fri Feb 03, 2006 11:07 pm
by Christopher
What version of PHP are you using. With PHP5 I get:

Code: Select all

1: testRegistry Object
(
    [_input] => snap1
)

2: testRegistry Object
(
    [_input] => snap2
)

3: testRegistry Object
(
    [_input] => snap2
)

4: testRegistry Object
(
    [_input] => snap3
)

5: testRegistry Object
(
    [_input] => snap3
)
What are you using the static calls for anyway? I try to do straight composition and stay away from static calls. I prefer the Registry over the Singleton -- I can't think of anywhere I use them anymore.

Posted: Sat Feb 04, 2006 4:43 pm
by John Cartwright
What are you using the static calls for anyway?
Wouldn't it eliminate the need to instantiate the class?
I try to do straight composition and stay away from static calls.
Sorry could you elabortate a bit more?

Posted: Sat Feb 04, 2006 4:59 pm
by John Cartwright
Well, I guess I'll take this as an excuse to finally upgrade.. thanks arborint :wink:

Posted: Sat Feb 04, 2006 7:21 pm
by Christopher
Jcart wrote:Wouldn't it eliminate the need to instantiate the class?
Well you are instantiating a class anyway. My question is why your architecture needs globals? To me those calls indicate that you don't have clean dependencies.
Jcart wrote:Sorry could you elabortate a bit more?
It may seem a pain, but passing object through the constructor oftens ends up creating the most testable and solid code in the long run in PHP. The dependencies are clear and the interface is polymorphic. The next step past composition is to in some way inject the object/methods into the object that need them. Not so easy in PHP.

Posted: Sat Feb 04, 2006 8:35 pm
by m3mn0n
Jcart wrote:Well, I guess I'll take this as an excuse to finally upgrade.. thanks arborint :wink:
Atta boy! PHP 5 ftw! :)