I have been told that Singletons are hard to test.
I have been told that Static methods/objects are no good either.
So basically the only solution appears to be dependency injection.
But ... I really can't get used to DI, take this example:
In my framework I have a class that manages SQL. This class (and many other of my framework) uses a singleton Logger to logs message (and many other helpers).
With DI my code would turn to:
global $logger; //> consider i have been instanciated it at the start of my fw
$query = new PreparedQuery($logger);
$query->prepare() etc.
Now that doesn't seem too bad. But consider a page that needs many queries I believe it's pretty redundant to have to write everytime $logger
in the constructor, especially if you consider if PreparedQuery needed many other dependencies in the constructor.
The only solution to avoid singleton that I have found is to use a method (or just a simple function) in the main application that stores every references to this helper objects (Service Locator/Container) but this doens't solve the problem of hiding the dependencies
So in your experience other than DI what is a good pattern to use?
For everyone interesetd the creator of PHPunit explains how to solve the Singleton problem (and how to solve static methods testing problem with PHP 5.3)
Pretty interesting read if you ask me.
The use of singletons and dependency injection is not mutually exclusive. A singleton can implement an interface, therefore can be used to satisfy a dependency on another class. The fact that it is a singleton does not force every consumer to obtain a reference through it's "GetInstance" method/property.
However, unlike a static class that can have only static objects, a singleton class can have both static and non-static objects. Hence from the perspective of memory management, you can take advantage of garbage collection for the managed objects when you're using a singleton class.
Singletons may or may not have state and they refer to objects. If they are not keeping state and only used for global access, then static is better as these methods will be faster. But if you want to utilize objects and OOP concepts (Inheritance polymorphism), then singleton is better.
A Singleton can implement interfaces, inherit from other classes and allow inheritance. While a static class cannot inherit their instance members. So Singleton is more flexible than static classes and can maintain state.
Please, don't use global
.
You need to pass $logger in constructors or pass Service Container instead (also known as Objects manager, Service Locator, Resources Manager).
Variant from Symfony framework http://symfony.com/doc/current/book/service_container.html
You can create your own Objects Manager, and his methods should not be static.
Well, in this case, I would build a builder (or factory) instead. So your factory would inject the dependency for you. That way you can also avoid your globals:
class PreparedQueryFactory {
protected $logger = null;
public function __construct($loggger) {
$this->logger = $logger;
}
public function create() {
return new PreparedQuery($this->logger);
}
}
That way, you do once:
$factory = new PreparedQueryFactory($logger);
Then any time you need a new query, just call:
$query = $factory->create();
Now, this is a very simple example. But you could add all sorts of complex logic if you need. But the point is, by avoiding new
in your code, you also avoid managing the dependencies. So instead, you can pass the factory(ies) around as needed.
The benefit, is that all of this is 100% testable, since everything is injected everywhere (as opposed to using globals).
You can also use a registry (otherwise known as Service Container, or DI Container), but be sure you're injecting the registry in.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With