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.