As we attempt to rewrite more and more pieces of Drupal (dbtng, t(), ..) in OOP code, we also see singletons being used or suggested.
Trying to not hijack other discussions and d.o. issues, I start a new discussion about this here.
Usually in debates about singletons, the alternative being suggested is not the "factory with static cache", but some fancy injection logic, that allows to totally get rid of global state. While this is nice, we have to consider that we are still in Drupal world, in a situation where "no global state" is not realistic mid-term. So, I want to compare two things that are actually fair to compare to each other.
Alternative I: Factory function with static cache
This is very close to what usually happens in traditional Drupal, although most of our static variables do not contain PHP5-style objects.
<?php
function get_instance() {
static $_instance;
if (!isset($_instance)) {
$_instance = new InstantiateMe();
}
return $_instance;
}
class InstantiateMe {
...
}
?>Someone might even call this thing a singleton - yeah, why not.
Alternative II: Singleton pattern
This is how you will usually find singletons being described in a book.
<?php
/**
* This function is optional, if we don't want calling code to write InstantiateMe::singleton()
*/
function get_instance() {
return InstantiateMe::singleton();
}
class InstantiateMe {
static protected $_singleton;
static function singleton() {
if (!isset(self::$_singleton)) {
self::$_singleton = new self();
}
}
...
}
?>More alternatives?
Yes, we could think of more ways to achieve the same, but I want to stick with these two examples for now.
The factory could be an object in itself (of a class different from InstantiateMe), or it could be a static class method (of a class different from InstantiateMe). The important part is that InstantiateMe does not contain any of the factory logic.
Differences
These are two more or less technically equivalent implementations.
- There is only one instance of InstantiateMe being created and then reused.
- The one instance is available via global scope functions.
- We could add some reset logic to both of these implementations.
- Both suffer from the typical global state disease with its side effects, that we have everywhere in Drupal. We have no choice but to accept this.
So, why would one choose one or the other of these two alternatives?
Here are some differences:
(from http://drupal.org/node/1213510#comment-4750250)
- The singleton has the static instance variable + creation logic in the same spot (class) as the class definition itself.
- The singleton does not choose between different implementations. It will always create an instance of itself, not of something else.
- Also, there can not be other systems that have their own statically cached instance of the class (with different parameters, if you want).
- Code that calls a singleton has to know the class name (and thus the type of return value). Code that calls a factory function only needs to know about the behavior of the returned object (which can be expressed in an interface, but doesn't have to). This allows the implementor of the factory to swap out the implementation by something else.
I read somewhere, and it made a lot of sense to me, that factory and "static cache" logic (don't remember the exact term) should be separate from the class implementation. I generally believe that everything should be in separate spots, unless there is a very good reason why it has to be in the same spot (coupling, etc).
So, IMO, a factory function + static cache (or some class/object for this purpose, that is not identical with the class to be instantiated) is almost always a better choice than a singleton.
The only reason why one would prefer a singleton is because in a it looks more "OOP" than a "floating function" factory. But honestly, it is not. "static" means to use classes as namespaces for global vars (ok, at least made invisible from outside) and floating functions. This has very little to do with oop.
There is also a "philosophical" difference:
With a singleton, we want to have no more than one instance of a specific class.
With static instance cache that is independent of the instantiated class, we want to have no more than one object for a specific purpose.
At first this might be identical, but the second philosophy is more flexible for future changes.
So, why is the singleton so popular?
The singleton pattern is still popular in libraries that have not yet made the step of saying goodbye to global state altogether - which can be for good reasons. I think, a simple factory/access function is not an option in most of these, simply because these guys don't like floating functions at all. Floating functions don't work well with autoload, and they don't fit into the usual directory structure based on class name.
Comments
Singleton is a pattern that
Singleton is a pattern that is used for having global state objects without having them pending in the global scope.
One of its biggest cons is that it break possibility to do dependency injection: because the singleton itself lives in static property of its own class.
That said, the fact that the singleton object must have the same class as the factory/accessor method that carry it is untrue: some frameworks uses a static accessor on an abstract or default implementation and, depending on the context, allows the initial object creation to create a specialization instead: this looks like a step towards dependency injection.
The factory procedural function as you describe does have the exact same pros and cons than the legacy singleton pattern: the only difference is that the accessor is in another namespace than the class itself (which is actually a cons because it breaks code consitency and make it harder to read).
Using a real factory, with dependency injection capabilities is a good thing to do if needed. The if needed part is really important, because it's not always actually needed.
In order to fulfill a complete dependency injection, the object that carries the factory accessor must have a setter function for setting the potentially injected instance: this allows external code to inject their dependency. An implementation using a default implementation carrying the factory method doesn't prevent us from doing that, even if in that case I would prefer the factory itself to be a higher layer leveled class that defines the scope where we currently are.
Food for though: when you have a factory object, you want this object to be in the global scope, so the problem here is you need then a singleton. In a lot of case this might be pure code indirection. In order to fulfill dependency injection from the start, there should be no static accessor at all, and the framework would need to be fully OOP (which Drupal isn't).
To conclude, the singleton pattern is the more efficient way to implement some other patterns. For example the null object pattern: create a stub and neutral implementation of a particular interface, that is used per default when nothing else is usable. I definitely would use a singleton for this object. By using a singleton for most of the neutral objects (without context) we can share memory whenever it's needed, in all part and scopes of the code. We don't need factories for neutral implementations because neutral is neutral, you can implement a thousand of neutral objects they will still do exactly the same thing because they are neutral per definition.
This was just some pieces of though: there is no debate to run about singleton, it's a commonly used pattern which as good use cases, and wrong use cases, as much as everything else: the real debate is on a per use case basis.
Pierre.
That said, the fact that the
This is actually the only thing this was all about.
I still had the classical/simple example of singletons in my head, where the accessor always returns an instance of self.
If we allow the accessor to return instances of something else (anything that implements a specific interface, but not necessarily a child of the same abstract class), then why not make it totally independent of the class we want to instantiate.
The thing is, we want to have one (statically cached) object for a specific purpose, not necessarily one instance of a specific class. There could be more than one such purpose, which need different instances of the same class. The "purpose" could be in a different package/module than the class implementation. And, there can more than one class that can fulfull the same "purpose". Even if, at design time, we only think of one purpose, and one implementation.
So, the only thing we are talking about here is, do accessor ("purpose") and implementation belong into the same class, or should the accessor be in an abstract base class, or should it be totally separate? I guess we are left with a matter of taste.
Exactly. So all the usual arguments vs singleton and global state and static accessors are not fair in the Drupal universe.
I think the argument of "where to put the static accessor and instance variable" applies to all cases where we want to use a singleton. Sometimes the "purpose" can be easily identified 1:1 with the implementation class, but even then, we might see different use cases in the future, where we want to reuse the class for a different purpose, or fill the static instance variable with something that does not even inherit from the abstract base class.
Advantage of Singleton
The advantage of the singleton is that it makes a very clear differentiation between the global data that may or may not directly impact the factory and the factory itself. If I have a WidgetManager (Singleton) and a WidgetFactory, I have two hopefully well defined roles for my classes. I shouldn't have to decide which data is global, which is local, what data my factory is using or ignoring. If I get the WidgetFactory from the WidgetManager, I can even swap out one factory for another, override global settings, or even hide the factory entirely for callers who are looking for all the default behaviors.
When not to use a Singleton
If the Singleton needs to present an interface that is as complicated as the factory it manages, you are probably better off statically caching the data in the factory clash. That is if the singleton is only used to cache data, you might as well just cache the data in the class. If the singleton can simplify life for many of the developers by presenting a simplified API (which it usually can, most developers will in all likelihood opt for default behaviors), the Singleton is easy to code and can hide a lot of complexity.