CHAPTER 12 ■ ENTERPRISE PATTERNS
The benefit here is that you don’t need to create methods for every object you wish to store and
serve. The downside, though, is that you reintroduce global variables by the back door. The use of
arbitrary strings as keys for the objects you store means that there is nothing stopping one part of your
system overwriting a key/value pair when adding an object. I have found it useful to use this map-like
structure during development and shift over to explicitly named methods when I’m clear about the data
I am going to need to store and retrieve.
You can also use registry objects as factories for common objects in your system. Instead of storing a
provided object, the registry class creates an instance and then caches the reference. It may do some
setup behind the scenes as well, maybe retrieving data from a configuration file or combining a number
of objects.
//class Registry...
function treeBuilder() {
if (! isset( $this->treeBuilder ) ) {
$this->treeBuilder = new TreeBuilder( $this->conf()->get('treedir') );
}
return $this->treeBuilder;
}
function conf() {
if (! isset( $this->conf ) ) {
$this->conf = new Conf();
}
return $this->conf;
}
TreeBuilder and Conf are just dummy classes, included to demonstrate a point. A client class that
needs a TreeBuilder object can simply call Registry::treeBuilder(), without bothering itself with the
complexities of initialization. Such complexities may include application-level data such as the dummy
Conf object, and most classes in a system should be insulated from them.
Registry objects can be useful for testing, too. The static instance() method can be used to serve up
a child of the Registry class primed with dummy objects. Here’s how I might amend instance() to
achieve this:
static function testMode( $mode=true ) {
self::$instance=null;
self::$testmode=$mode;
}
static function instance() {
if ( self::$testmode ) {
return new MockRegistry();
}
if (! isset( self::$instance ) ) { self::$instance = new self(); }
return self::$instance;
}