Home > OOP, PHP > Putting the Singleton-pattern to good use

Putting the Singleton-pattern to good use

I like the Singleton-pattern, it saves a lot of trouble on creating objects that you need throughout your code and need to keep their state. Though it’s very tempting, do not use the singleton too much; see here why.

There are some pretty good uses for a Singleton though; a registry and the database-connection;

Download example code here

Database-connection

I use ADODB to access databases, don’t ask me why, I just do. ADODB uses a DSN to connect to a database, which looks something like:

mysql://dbUser:dbPass@localhost/someDb

Normally you’d use $connection = &ADONewConnection($DSN) to connect to the database and run your query ($rs = $connection->execute($sqlQuery) ). The problem here; you keep creating new connections anywhere you run a query, you need to pass the value for $DSN into your objects,  you’ve made your class depend on ADODB and it take 2 lines of code ;)   You can bypass these ‘problems’ by using a Singleton to connect to your database and run a query:

$rs = basicDBConn::getConnection()->execute($sqlQuery);

Now, what is wrong here? Did you see $DSN anywhere?
Nope… This statement assumes you’ve passed $DSN already somewhere before, in fact the first time you call getConnection() from this singleton you must pass $DSN as argument in getConnection(). The first time you call getConnection() is the moment the singleton creates an instance of itself, and uses $DSN to connect to the database (&ADONewConnection($DSN)). After this initialization the connection is kept within the Singleton, and $DSN isn’t needed anymore. Take a look at the files, basicDBConn.php in particular to get an idea of how the Singleton creates an instance of itself and the database-connection.

Registry

Another good use for Singletons is a Registry-object; A registry-object is used for configuration; global settings that you might need in your code (path’s, DB-configuration etc.). Since I’m infected by the XML-virus my configuration-files always are XML :

<config>
    <item index="DSN">mysql://dbUser:dbPass@localhost/singletondemo</item>
    <item index="someKey">someValue</item>
</config>

There is a drawback though; these XML-files are not protected by Apache by default, anyone can open them from a browser (if they are somewhere in the public root of the website). There are 2 solutions for this; prefix the file with .hta (in which case Apache will protect them just as .htaccess files are protected) or add the following lines to your Apache-configuration :

<Files ~ "configuration_filename.xml">
   Order allow,deny
   Deny from all
</Files>

The registry-object works the same as the Database-object; it needs a reference to a XML-file the first time you call it, after that it’s fully initialized and doesn’t need that reference anymore.

The first call to a registry object (and get the value for ’some_key’):

$someValue = basicRegistry::getInstance('/path/to/configuration/file.xml')->get("some_key");

Any call after that:

$someValue = basicRegistry::getInstance()->get("some_key");

Why is a singleton a good thing?
Getting configuration-values or a $DSN-string from within objects should be simple, you do not want to pass the path and filename to your configuration file or $DSN to a database every time you create an instance of an object. It will create dependencies and spaghetti in your code. If you make sure the registry and/or database-object are created before your other objects start doing something you do not need to worry about file-names and/or $DSN’s. They have been safely put away in a singleton.

Another very nice side-effect ; you’ve decoupled database-connections and configuration-settings. In my examples I use XML to setup the values in the registry, if you want to use some other method of keeping key-value-pairs, just modify the inner workings of the Registry-singleton, the objects using the registry won’t notice and work just as well. I usually keep session-variables in the registry, if I can’t use PHP’s $_SESSION, I can fall back onto Cookies, my classes won’t notice.

Download example code here

Share this post:
  • Twitter
  • Facebook
  • Digg
  • del.icio.us
  • FriendFeed
  • Technorati
  • Google Bookmarks
  • PDF
  • Print
  • NuJIJ
  • Ping.fm
  • StumbleUpon
  • Symbaloo
  • Hyves

buTTon OOP, PHP , , , ,

  1. alex
    May 15th, 2009 at 17:02 | #1

    so your registry effectively creates a login details holder too?

  2. May 16th, 2009 at 07:07 | #2

    the downloadable version doesn’t read/write from/to session variables, but if you’d add:

    foreach($_SESSION as $index=>$value){
    $this->myValues[$index] = addslashes($value);
    }

    To the init() function you should be able use sessions to identify if a user has logged in.
    Though it’s optional you should add some method to write to $_SESSION, if you’re using it on a server that doesn’t have session-support you’d only need to change the registry class to use Cookies instead of Sessions, leaving all your other code in tact (and decoupled):

    public function setSession($key, $value){
    $this->myValues[$key] = $value;
    $_SESSION[$key] = $value;
    return $value;
    }

  3. Sapan Shah
    July 2nd, 2009 at 09:28 | #3

    Hi
    I also love the singleton approach and have quite used them in many applications.

    My problem is for configuration at database level. I read the configuration details from the database at one go and then whenever required, I access the object rather than the database. My question is if suppose the database table is manipulated using SQL queries, then how am I supposed to refresh the same at the object level without having a database hit whenever my web page is requested which uses the database configurations.

  4. July 2nd, 2009 at 12:19 | #4

    @Sapan Shah
    You should use a method in the singleton-class that changes values in the database (never outside the class). This way you can update the value in the singleton itself and execute an update on the database. Since it’s a singleton you should be able to refer to the object from practically anywhere in your application to changes values.

    I usually have 2 “set-values” functions in my registry-singleton; a normal “set” function ( $obj->set($key, $value) ) that only adds/modifies a value in memory (not database) and $obj->setReg($key, $value) that will also add/modify the value in the database.

  1. May 3rd, 2009 at 08:47 | #1

Onze tip:SCDB.info – de meest actuele flitspalen in Europa voor uw GPS!