Page 1 of 1

Clean Singleton

Posted: Wed Feb 06, 2008 9:00 am
by Bon Bon
A lot of people seem to have their own version of how a singleton should be programmed in PHP. I thought it would be a nice idea to start a topic where people publish their own version and why they have done what they have done so that others can learn and an overall standard design can be achieved.

Code: Select all

// singleton class
class Singleton_Example {
  // ensure there is only ever 1 singleton, NULL because no object exists as of yet
  static private $_instance = NULL;
 
  // static method getInstance because we are calling the method statically 
  static public function getInstance () {
    // returns a reference to the singleton object instance if one exists or creates a new instance of the object and returns the reference
    return self::$_instance === NULL ? self::$_instance = new self : self::$_instance;
  }
}
 
// autoload an instance 
$singleton = Singleton_Example::getInstance();

Re: Clean Singleton

Posted: Wed Feb 06, 2008 9:07 am
by Zoxive

Re: Clean Singleton

Posted: Wed Feb 06, 2008 9:39 am
by Bon Bon
The problem I have noticed with singletons is when you initiate an instance you cannot pass arguments to the constructor because you are forced to call the getInstance method.

It would be great if somebody had a solution to the problem so that instances could be loaded dynamically depending so that say for instance each user had their own database, the getInstance could load the specific database for that user like so $db = Database::getInstance($username, $password) which would then load __constructor($username, $password)

Has anybody ever thought about anything like this before?

Re: Clean Singleton

Posted: Wed Feb 06, 2008 9:43 am
by Zoxive
Bon Bon wrote:It would be great if somebody had a solution to the problem so that instances could be loaded dynamically depending so that say for instance each user had their own database, the getInstance could load the specific database for that user like so $db = Database::getInstance($username, $password) which would then load __constructor($username, $password)
Then it really isn't a singleton then. It sounds like you need a registry with normal Classes stored in it, so throughout your application you can use those instances of the class.

http://www.patternsforphp.com/wiki/Registry

Re: Clean Singleton

Posted: Wed Feb 06, 2008 9:55 am
by Bon Bon
A registry to me is just a duplicate of accessing a database but with an easier interface.

The example below is limited because the number of arguments that can be passed between the constructor and the getInstance method is limited to what is defined, this would have to be modified in each different class you required the same sort of referencing:

Code: Select all

// singleton class
class Singleton_Example {
  // ensure there is only ever 1 singleton, NULL because no object exists as of yet
  static private $_instance = NULL;
 
  // static method getInstance because we are calling the method statically
  static public function getInstance ($username, $password) {
    // returns a reference to the singleton object instance if one exists or creates a new instance of the object and returns the reference
    return is_null(self::$_instance) ? self::$_instance = new self($username, $password) : self::$_instance;
   }
 
  private function __construct ($username, $password) {
    self::$_db->real_connect('127.0.0.1', $username, $password, 'user_' . $username);
  }
}
  
// autoload an instance
$singleton = Singleton_Example::getInstance($username, $password);

Re: Clean Singleton

Posted: Wed Feb 06, 2008 10:08 am
by Zoxive
The thing is, you are moving away from what a singleton is. Singletons are the same thing every call. When you start passing different things to it, or start passing anything at all to singletons, they really are no longer singletons. Just normal Classes.

That's why I suggested a Registry, in the very beginning of your application you can store the classes with the parameters passed to them as you need in the registry, and then are able to call those classes anywhere. In a since, the Registry is a singleton, holding the classes as they were initiated.

Can you explain more of what you are doing, and what kind of system/pattern you using, so we can get a better idea of what you are trying to accomplish?

Re: Clean Singleton

Posted: Wed Feb 06, 2008 11:00 am
by Bon Bon
To be honest this was just something I was thinking about. Whenever I only allow 1 instance of an object I always start the object by appending the class with a line to create a reference to the instance. This just makes it easier to work globally throughout the PHP even if on the off-occasion the object will never be used.

I just thought that singletons have limitations that some may hay have experienced and the vast array of singletons out there also means that there must be reasons why some programmers write a singleton one way while others write them another way.

Re: Clean Singleton

Posted: Wed Feb 06, 2008 11:25 am
by Christopher
Zoxive wrote:The thing is, you are moving away from what a singleton is. Singletons are the same thing every call. When you start passing different things to it, or start passing anything at all to singletons, they really are no longer singletons. Just normal Classes.
Singletons are not exactly defined as being "the same thing every call", they are an implementation where there is only one instance in the system. There is no constraint that that single instance cannot change internally. So it could be a database connection object that can close a connection and then connect to a different database when asked to. But as you can see, a Factory would probably be a better choice. Such is almost always the case -- there is usually a better implementation than using a Singleton. This is less true in long running programs, which PHP is not.

Re: Clean Singleton

Posted: Wed Feb 06, 2008 11:33 am
by Zoxive
arborint wrote:Singletons are not exactly defined as being "the same thing every call", they are an implementation where there is only one instance in the system.
I guess what I meant was they are called the same way every time. :banghead: (Without constructors)

The only thing about them changing is, What if your code was expecting it to be on database A, when earlier it was Changed to B. As soon as you start changing you need to have the singleton to get smarter, so it can adapt to what it is being called for. Which could complicate things dramatically.

Re: Clean Singleton

Posted: Wed Feb 06, 2008 11:59 am
by Christopher
Exactly! :)

Re: Clean Singleton

Posted: Thu Feb 07, 2008 8:53 am
by Bon Bon
The only thing about them changing is, What if your code was expecting it to be on database A, when earlier it was Changed to B.
Good point, I had already thought about this and by allowing variables to be passed on construction means that only the first call would actually allow A to change to B.

The whole theory of this is that a dynamically generated singleton would open the door to new possibilities when programming.

Re: Clean Singleton

Posted: Thu Feb 07, 2008 11:59 am
by Christopher
Bon Bon wrote:The whole theory of this is that a dynamically generated singleton would open the door to new possibilities when programming.
I think if you read more about Singletons you will find that they appear fascinating at first blush, but most programmers find that removing them is eventually the best course of action. You can read about why by searching these forums and the web. The problem relates to the larger problem of globals which programmers usually code around until complexity reaches a certain point.

Re: Clean Singleton

Posted: Thu Feb 07, 2008 1:19 pm
by dreamscape
To answer the question of dynamically passing function arguments to a constructor with an unknown function declaration, you could probably accomplish this using ReflectionClass::newInstanceArgs() with func_get_args().

Re: Clean Singleton

Posted: Mon Feb 11, 2008 7:20 am
by Bon Bon
To be honest I think a singleton is the best way of calling a database connection because you then only have 1 instance of a database connection at any 1 time which is why I used a dynamic database connection as an example.

I have already looked at func_get_args but I could not think of a way of passing these arguments to the constructor because I was reading around PHP.net and there were some ways of doing this but they all had drawbacks.

Obviously a singleton should not be used for everything and it is probably bad practise to actually create a dynamic database connection, which relates more to databases than PHP but at the end of the day I was just wondering what others were doing, being nosy really but the idea of a singleton interests me too as there are lots of versions which obviously says something about singletons to me.

Re: Clean Singleton

Posted: Wed Feb 13, 2008 12:54 am
by timvw
Bon Bon wrote:To be honest I think a singleton is the best way of calling a database connection because you then only have 1 instance of a database connection at any 1 time which is why I used a dynamic database connection as an example.
But php handles this issue already (read: you have to make some extra efford in order to get two different connections to the same dbms)...