The Registry Pattern Reexamined

« »

Last July, I wrote about the registry pattern and some of its advantages. These advantages include the ability to access objects across different areas of your application, and the storage of objects for later retrieval.

Much of the debate in the comments focused on whether or not the registry pattern was suitable for today’s object-oriented development, and some of the arguments focused on whether or not the “global scope” was a good place to have objects.

For me, over the last few months, I’ve discovered two reasons why I advise against the Registry Pattern: first and foremost, it discourages unit testing, and secondly, it discourages good design.

Unit testing is predicated on the assumption that you are testing small, discrete units of code that do not have dependencies. This requires that developers do everything they can to either remove dependencies or mock them in such a way that the dependencies are neutralized as contributors to the failure of the unit being tested. In PHP 5, objects are not copied when assigned; instead, their address in a hash table is copied. This means that if you retrieve an object from the registry, and then modify it, every subsequent retrieval from the registry will reflect that modification.

The reason this creates a significant issue is that it prevents you from testing a discrete unit of code. Now, instead of one thing being the variable in a test failure, there are two: the unit of code being tested and the object it retrieved from the registry. Any time there is more than one possibility for failure, the effectiveness of the unit testing is diminished.

As a side note, the same holds true of singletons: modifications to the singleton object will be reflected in every other test performed during that request, thus reducing the efficacy of the unit tests.

Secondly, I’ve found that the registry pattern promotes poorer design overall. The reason for this is clear: because you can store an object for later use, there is no need to consider the path through the application that the object might otherwise need to travel. There’s no determination where, when and how to get the object to where it is needed. You can simply pull it from thin air on demand. This leads to developers being lazy about their architecture, and ultimately leads to poorer code (which you can’t determine through tests because the objects keep changing during testing!).

Dependency injection forces developers to think about why they’re doing what it is that they’re doing. Moreover, using dependency injection means that you’re more likely to employ good development practices like abstraction, composition over inheritance, etc. The reason for this is because as a developer, when you start injecting three or four or five objects, you begin to consider why; this often leads to a refactoring, and ultimately a better finished product.

As I stated before, design patterns are not the problem, and each design pattern has an important reason for existing and solves a very real problem. The registry pattern shouldn’t be forbidden or never practiced, but it should be practiced sparingly, along with all other design patterns, because it isn’t a one-size fits all solution.

Brandon Savage is the author of Mastering Object Oriented PHP and Practical Design Patterns in PHP

Posted on 3/26/2010 at 7:00 am
Categories: Object-Oriented Development, Technology, Best Practices
Tags: , , , , , ,

Matic wrote at 3/26/2010 8:13 am:

PHP already has a built in registry, it’s $GLOBALS and I really like it because it makes code simpler. To store a value in cache I simply use:

$GLOBALS[‘cache’]->set($key, $value);

I use similar commands for DB access, sending debug info to Firebug, current user data (language, locale, timezone, location, …) and similar. Basically, stuff I need easily accessible from everywhere.

It’s good for me and has never caused me any problems. It’s part of the framework I’ve created. It’s what frameworks are for.

I don’t understand your POV.

fqqdk (@fqqdk) wrote at 3/26/2010 8:46 am:

yay :) good to see another fellow coder on this side of the religious schism :D

Matthew Weier O'Phinney (@mwop) wrote at 3/26/2010 9:21 am:

The Registry pattern you speak of here is better termed a Global Registry or Static Registry.

You can also have a Registry that is neither global nor static, and which is passed around between objects or which acts as an internal registry for an object with many collaborators. We use the pattern in Zend Framework on Zend_Application_Bootstrap, which uses a Registry internally to keep track of bootstrapped resources for later use.

Jake Smith (@jakefolio) wrote at 3/26/2010 9:55 am:

I’m a fan of DI and usually have core objects stored (DB, Log, Session, etc). I can understand why newer developers can fall in love with the Registry Pattern….”I can access any of my objects….at anytime? sign me up!”.

Great post on why you shouldn’t “overuse” Registry and with alternative solutions.

Dwayne Holmberg wrote at 3/26/2010 1:27 pm:

The registry love going around lately has been disturbing me. I’ve used it extensively in the past and ran into a couple of other problems as well:

1) you don’t know what is using items pulled from the registry, so you don’t know where modifications to those might be being made. It’s a whole new level of spaghetti that makes debugging hell.

2) using keys to reference items in the registry becomes problematic because they are easier to add then they are to document. (For a similar reason, I prefer explicit setters to option arrays, which is another religious debate.)

Registry is seductive because it’s easy right now, while you’re in the code, but it’s a short term payoff.

Les wrote at 3/26/2010 2:18 pm:

I still use Registry today however I tend to use it indirectly, for example this way


public function getConnection() {
if( is_null( $this -> db ) ) {
$this -> db = Registry::get( ‘db’ );
}
return $this -> db;
}

You now have a default connection or use a setter to set a different one. Too many applications use DI when that is over the top IMHO; do remember the wrong tool can do just as much damage.

Leonard Dronkers (@leonarddronkers) wrote at 3/26/2010 3:26 pm:

I have seen abuse of the (static/global) registry pattern where stuff is just dumped in there. And then picked up at will(in library code for example…) Not a good practice.

That said, it can come in handy… just a matter of proper usage.

Tom wrote at 3/26/2010 4:20 pm:

I understand your pov but how would you handle global configuration and db connections passing it around trough all THE objects seems not very handy

Flavius Stef (@flaviusstef) wrote at 3/26/2010 7:07 pm:

1) I would argue that adding setter methods to the Registry solves the testing problem. Running Registry::setDatabase($mock) prior to the code being tested takes care of the coupling.

2) If not using a DI framework, but a ServiceLocator instead, the Registry is a proper fit for all of the configuration-wide objects (database connection, logger, configuration parameters etc.)

James wrote at 3/26/2010 7:13 pm:

@Matic: Globals are actually considered an anti-pattern (http://c2.com/cgi/wiki?GlobalVariable). There are a few very good reasons not to use them:

First, in PHP, there is nothing protecting globals from being changed. Some well meaning, but unknowing, developer might not realize that the “cache” global is already being used. They assign a different value to the variable and are happily on their way. Now you have a bug that is caused because of their code, but manifests itself in yours. These can be brutal.

Second, global state hides dependencies. I usually compare it to “f(X) = Y”. When you plug in X, you should always get Y as the return value. If changing a global affects the result of a function, then it is really a hidden argument. Suddenly, you have to know about the inner workings of the method to understand why f(X) now returns Z. Really, your method is f(X, GLOBAL) = Y. This can be really become a problem when trying to do Test Driven Development. Globals make writing tests a pain in the arse.

Anyway, I recommend taking a look at Misko Hevery’s blog (http://misko.hevery.com/). He has written quite a bit about testability and dependency injection. Suffice to say, he is an avid opponent of Globals (and Singletons).

Miles Johnson (@gearvosh) wrote at 3/26/2010 11:58 pm:

There are many different ways to use the Registry pattern. But if I want to retrieve an instance of an object in multiple places and have them all update each other, than I would use a Registry.

The Registry however should not run the core/framework of your App, it should simply be a convenience.

Les wrote at 3/27/2010 6:43 am:

@Miles

That is very true; the Registry should only be used in application code.

I made provision for passing objects along the layers in my own framework so I can easily begin a new application without useing Registry at all.

@Leonard

Very true and that is being openly abusive of the Registry design, developers with little or no understand should just step aside IMHO.

Jiri Fornous wrote at 3/29/2010 3:37 am:

I think nobody has mentioned the main reason why registry pattern is used – it’s because of state serialization (mostly on model). It’s very easy to travers all your objects created without knowing them. Since there is always a way how to register objects and also follow good programming practice (DI).

Tibo Beijen (@TBeijen) wrote at 4/2/2010 3:56 am:

As a rule of thumb I use a registry only to store and retreive objects that are read-only (config) or ‘use-only’ (db, log, factories).

When you use a registry as a ‘convenient tool’ to transport objects (holding data that might change throughout code execution) from A to B, alarm bells should start to ring…

Ahmed Shreef (@shreef) wrote at 4/13/2010 9:08 pm:

using a setter with optional parameter can allow you to Inject your Dependencies and use Registry at the same time.

public function setDb($obj=null) {
if ( $obj !== null ) {
return $this->_db = $obj;
}

return $this->_db = Registry::get(‘db’);
}

you can write unit tests for this class simply this way and you are still using Registry.

« »

Copyright © 2023 by Brandon Savage. All rights reserved.