SiteCrafting Blah Blah Blog

Sep. 27, 2007 at 3:17pm

PHP Patterns, Part I

The Registry Pattern

This is the first in a planned series of articles discussing the application of various PHP patterns. If you're still getting your feet wet developing in PHP (or programming languages in general), you may be wondering what a "pattern" is in the first place. The best place to find a quick explanation is over in Wikipedia's article (which does a much better job than I could hope to do within the scope of this article).

Now, let's move on to the fun part . . .



I. The Registry Pattern, an Introduction
I am going to kick off this series by introducing you to the registry pattern. First, imagine you are deep into a complex web application and you come to the realization that you have several objects that all require access to your database. Your first inclination may be to simply have each class initiate their own connection to the database and use it as they please. But then you'll start to hear that little voice in the back of your head, screaming something about how you're needlessly wasting valuable system resources and bandwidth. Naturally you ask what else you could do - this is where  a registry comes in handy.

A registry object basically acts as a container for objects that you want to be universally accessible throughout your project, while avoiding the use of . . . gulp . . . global variables! You'll find that its implementation is fairly simple, but extremely powerful and convenient.

II. Class Definition
Let's take a look at what a registry class is made of:

class Registry {
    protected
$_objects = array();

    function
set($name, &$object) {
       
$this->_objects[$name] =& $object;
    }

    function &
get($name) {
        return
$this->_objects[$name];
    }
}


Look at that! Pretty short and sweet eh? Now let's rip it apart and see what each component does:

  1. Following the class definition, we have a protected class variable called $_objects which is an array that holds all the objects that are added to the registry.
  2. Next we find our first function called set which is inherently public. This function is used to add an object instance to the registry. You pass it the object instance, and pick a friendly name to remember it by (don't forget it, you'll need it later!).
  3. Finally we have our second and final function get which retrieves an object previously added to the registry. Simply supply the friendly name you picked earlier and it will return the instance to you.

    You may be wondering what that ampersand (&) is doing up in front of the function name. This tells the function to return the object by reference rather than making a copy of it and returning the copy (which would make all this work pointless, since we again would be wasting resources). This means that any changes or actions performed on the object will be reflected everywhere else it is used in your application.

III. Less Talk, More Action!
Now that we have the basic concept outlined, let's take a look at how we might use our new creation. Let's say we have a simple class that returns a user's name, and another class that checks if a given user has "admin" status. In practice you would probably group this functionality into a single class, but for the sake of illustration we will pretend Captain Obvious is on vacation:

// First we create our database and registry
// objects
$db = new databaseConnection();
$registry = new registry();

// Then we add the db object to the registry
// It will now be available anywhere the registry
// is also available!
$registry->add("database", $db);

// Now we create the objet that gets our username
// and checks for admin status
$user = new username($registry);
$admin = new admin($registry);

$username = $user->getUser(12);
$isAdmin = $admin->check($username);

// Finally, we display the user's info
echo("Username: ".$username."<br />");
echo(
"Is Admin? ".$isAdmin);


Now, you'll have to use your imagination to see how the two objects are able to use the same database instance, but let's take a peek into what they both do:

//----- snip -----

// First they get the database object from the
// registry
$databaseObj = $registry->get("database");

// Then they use it as they see fit
$databaseObj->query("SELECT username FROM users".
    " WHERE id=$userId"
);

//----- snip -----


Congratulations, you have just learned how to create and use a registry! Now go forth and use what you have learned to write more efficient code!

Posted in Coding Techniques, PHP, Software Engineering by Nick Williams

Comments (7)

Dave says:

How would this work in a real world scenario? Since php uses the global database object transparently, it's not essential to put the registry wrapper around it.
1 | Oct. 1, 2007 at 1:44pm


I think you have a bug. Where you use $registry::set you have the arguments the wrong way round. Apart from that, thank you for showing this, never knew it could be so easy.
2 | Left by Luke L | Oct. 2, 2007 at 1:32am


Nick says:

Thanks for the sharp eye! Should be fixed now . . .
3 | Oct. 2, 2007 at 5:41pm


Nick says:

@Dave You have a good point. It was more for illustrative purposes than anything else, though it would make sense if you are using a database abstraction layer like PEAR::DB (it has been my friend on many a project ;-) ) which usually isn't made global implicitly.

The web framework I've been working on for a personal project has made use of this pattern quite a bit - in that case I have it storing my PEAR::DB object, my logger, and a "user" object storing user account info (so a query doesn't have to hit the db on every page load). Ah but I digress! I'll save it for another blog entry :-)
4 | Oct. 2, 2007 at 5:47pm


The $GLOBALS array already works this way, with much lower overhead.

Taking your example, instead do
$GLOBALS['database'] = new databaseConnection();
And from that point on, $GLOBALS['database']->query() is available from everywhere, in any scope.
5 | Left by Tino Didriksen | Oct. 25, 2007 at 4:57am


@Tino: The advantage of the Registry pattern is that it gives you /controlled/ access to the data stored in it.
You have the ability (should you require it at a later date) to intercept and modify requests for objects whenever and wherever you like!
6 | Left by Alex Barrett | Oct. 26, 2007 at 7:07am


This registry pattern is really interesting.
Anyway, I do not understand why you are still using a php4 syntax instead of the new php5 one ???
For instance, do we still need this '&' in your Registry class ?
Also, in part II (DAO and VO patterns), you could use __construct() instead of UserDAO().
If your purpose was to write a php4-compliant code, then please tell it at the beginning of your articles.
My point is that we should not use any php4 syntax anymore (all the more in object oriented patterns), just forget it as quickly as possible...
As for your database example, could we use here a Singleton pattern instead ? If yes, then I guess that the Registry pattern is more general as it can be used to store many instances...
7 | Left by Etienne Pallier | Nov. 19, 2007 at 4:42am


Remember me
Name: Email: URL: Comment: *   No HTML, http:// will auto-link
* required    Comment Guidelines