Page 1 of 1

Singletons, Registries, and GLOBALS

Posted: Fri Mar 10, 2006 12:04 am
by neophyte
The point of singletons and registries is to be able to instantiate an object such as a database object once and be able to call it in a different class with out having to instantiate a new object or pass it by reference into the object.

So far what I've read says this is best done through static variables in functions or methods. But what would be wrong with doing something like:

Code: Select all

function set_global( &$object, $handle = '' ){
		$class =(empty($handle))? get_class($object): $handle;
		$GLOBALS[$class] = &$object;
	}
	function get_global($handle){
		return $GLOBALS[$handle];
	}
functions are global and $GLOBALS will hold the value...

Seriously is this a good substitute? Is this just the same pattern reworked? Bad idea? Would like feed back....

Thanks

Posted: Fri Mar 10, 2006 12:26 am
by feyd
neophyte wrote:Seriously is this a good substitute?
I feel it's somewhat of a personal preference depending on how OOP you want to be or whether you feel that a many entries in the $GLOBALS array is better than one or none, depending on the "alternate" implementation. So all I can really say is I prefer Singletons and Registries over "standard" globals, however none of the directions are what I consider "prefect" or "optimal" ..

Posted: Fri Mar 10, 2006 2:17 am
by Chris Corbyn
I'm not even sure if your approach may perhaps be slower... I'd have to test that. You've kind of removed the whole side OOP that brings you encapsulation though since you've downright forced globals there. Your approach would work well nicely yes even in non OO frameworks -- in fact, I used to store the resource id in the session.

Posted: Fri Mar 10, 2006 3:07 am
by Maugrim_The_Reaper
It'd work fine - might cause some confusion (which may be a good point) about where the instantiated object is actually stored. In a singleton, the class locates an instantiated object in a static variable. Globals although workable just don't seem half as tidy.

Re: Singletons, Registries, and GLOBALS

Posted: Fri Mar 10, 2006 4:50 am
by Christopher
The problem is that the code you posted is that it does not provide the protection from the real problem with globals -- that you cannot isolate your dependencies. Any code that uses those functions has a potential dependancy on every piece of code in your application because you can do $GLOBALS['foo'] = 'overwrite the value'; anywhere in the code. If you use a Registry you have clear dependencies.

Posted: Fri Mar 10, 2006 6:10 am
by Chris Corbyn
Are you just thinking more about how to reduce the amount of typing or fetching of item from the registry? If you're using PHP5 have you looked into using an inherited registry? This way the registry contents will be quickly accessible by any object that inherits from it (stick the registry somewhere toward the bottom of the hierarchy).

I was just going over this with my boss about ten mins ago so here's a demonstration :P

Code: Select all

<?php

error_reporting(E_ALL);

//This would hold your database instance as static, it will also contain wrappers
class db
{
	static private $instance = null; //This will hold an instance of itself
	
	private $dbConn;
	
	private function __construct($host, $user, $pass, $name) //Note that this is private
	{
		$this->connect($host, $user, $pass);
		$this->selectDb($name);
	}
	
	static public function getInstance($host, $user, $pass, $name)
	{
		if (self::$instance == null)
		{
			self::$instance = new db($host, $user, $pass, $name); //Only creates object once *ever*
		}
		return self::$instance;
	}

	public function connect($host, $user, $pass)
	{
		$this->dbConn = mysql_connect($host, $user, $pass);
	}

	public function selectDb($name)
	{
		mysql_select_db($name, $this->dbConn);
	}
	
	/*
	 Some other wrapper functions here
	 */
	
}

class registry
{
	protected static $handlers = array();
	
	static public function add($name, $data)
	{
		if (!isset(self::$handlers[$name])) self::$handlers[$name] = $data;
	}

	static public function del($name)
	{
		if (!isset(self::$handlers[$name])) unset(self::$handlers[$name]);
	}

	protected function __get($name) //Overloaded getter
	{
		return self::$handlers[$name];
	}
}

//This is your typical class, with the registry somewhere at the base of the hierarchy
class foo extends registry
{
	function __construct()
	{
		//
	}

	public function reflect($obj)
	{
		print_r($this->$obj); //You'll see a DB object in here!
	}

	public function dump()
	{
		print_r($this);
	}
}

registry::add('db', db::getInstance('localhost', 'someuser', 'pass', 'www')); //Stick a database object in the registry

$obj = new foo;
$obj->reflect('db');

/*
 db Object
 (
     [dbConn] => Resource id #2
 )
 */

?>
So from inside the object you have access to $this->db->whateverMethod() at all times.

Posted: Fri Mar 10, 2006 9:31 pm
by neophyte
Wow! Thanks for all your comments.

I think I've decided that this is an okay solution as long as you're dealing with 2,3 maybe 4 objects in a small app (especially in php4). But for php 5 I think doing it that way would be just silly... Especialy on a big project.

As always I've learned a lot from your posts!

On a side note:
I got a new puter at work today! Very nice box and 0' course its a dual boot with Kubuntu.

:)

Posted: Tue Mar 14, 2006 7:19 am
by fastfingertips
I hate globals.

Since you are able to create a nice singleton (d11wtq you should know that you may scary people that are seeing private constructors :p ) why we should store tons of data in globals? I think that this is a designing problem.