The answer below is wrong, but I'll keep it for others to learn from it (see below)
In ExampleA
, you can use the same Config
instance across multiple classes. However, if there should be only one Config
instance within the entire application, consider applying the Singleton pattern on Config
to avoid having multiple instances of Config
. And if Config
is a Singleton, you could do the following instead:
class ExampleA
{
private $config;
public function __construct()
{
$this->config = Config->getInstance();
}
}
$exampleA = new ExampleA();
In ExampleB
, on the other hand, you'll always get a separate instance of Config
for each instance of ExampleB
.
Which version you should apply really depends on how the application will handle instances of Config
:
- if each instance of
ExampleX
should have a separate instance of Config
, go with ExampleB
;
- if each instance of
ExampleX
will share one (and only one) instance of Config
, use ExampleA with Config Singleton
;
- if instances of
ExampleX
may use different instances of Config
, stick with ExampleA
.
Why converting Config
into a Singleton is wrong:
I must admit that I only learned about the Singleton pattern yesterday (reading the Head First book of design patterns). Naively I went about and applied it for this example, but as many has pointed out, one way are another (some have been more cryptic and only said "You're doing it wrong!"), this is not a good idea. So, to prevent others from making the same mistake that I just did, here follows a summary of why the Singleton pattern can be harmful (based on the comments and what I found out googling it):
If ExampleA
retrieves its own reference to the Config
instance, the classes will be tightly coupled. There will be no way of having an instance of ExampleA
to use a different version of Config
(say some subclass). This is horrible if you want to test ExampleA
using a mock-up instance of Config
as there is no way to provide it to ExampleA
.
The premise of there will be one, and only one, instance of Config
maybe holds now, but you cannot always be sure that the same will hold in the future. If at some later point it turns out that multiple instances of Config
will be desirable, there is no way of achieving this without rewriting the code.
Even though the one-and-only-one instance of Config
is maybe true for all eternity, it could happen that you want to be able to use some subclass of Config
(while still having only one instance). But, since the code directly gets the instance via getInstance()
of Config
, which is a static
method, there is no way to get the subclass. Again, code must be rewritten.
The fact that ExampleA
uses Config
will be hidden, at least when just viewing the API of ExampleA
. This may or may not be a bad thing, but personally I feel that this feels like a disadvantage; for instance, when maintaining, there is no simple way of finding out which classes will be affected by changes to Config
without looking into the implementation of every other class.
Even if the fact that ExampleA
uses a Singleton Config
is not a problem in itself, it may still become a problem from a testing point of view. Singleton objects will carry state which will persist until the termination of the application. This can be a problem when running unit tests as you want one test to be isolated from another (i.e. that having executed one test should not affect the outcome of another). To fix this, the Singleton object must be destroyed between each test run (potentially having to restart the whole application), which may be time-consuming (not to mention tedious and annoying).
Having said this, I'm glad that I made this mistake here and not in the implementation of a real application. In fact, I was actually considering rewriting my latest code to use the Singleton pattern for some of the classes. Although I could easily revert the changes (everything is stored in an SVN, of course), I would still have wasted time doing it.