-- Ed Lazor <[email protected]> wrote
(on Thursday, 23 July 2009, 02:22 PM -0700):
> I realize some people are saying that Singletons should never be used.
>  If that's the case, why are they used in Zend Framework?   For
> example, Zend_Auth, Zend_Registry, Zend_Loader_Autoloader, and
> Zend_Controller_Front.  Aren't these good examples of where Singletons
> are beneficial?

Some are, and some are not.

Zend_Auth, Zend_Session, and Zend_Loader_Autoloader are examples where
they make sense. There is only one $_SESSION superglobal (Zend_Auth is a
singleton because it utilizes Zend_Session under the hood), and only one
spl_autoload registry; what they each operate on is singular in nature,
and thus the singleton makes sense. (That said, because $_SESSION is
globally available, Zend_Session could easily be refactored to remove
the singleton as well.)

Zend_Registry is an interesting hybrid. The main use case most people
write towards is its global registry nature. However, it can also be
instantiated directly and used as a local registry (Zend_Tool uses it in
this way, as does Zend_Application). I personally only ever use
Zend_Registry as a global registry when debugging -- I'll place a log
object in it and pull that to log information from my controller,
models, or views... but I *always* strip those calls out once the
problem has been isolated.

Zend_Controller_Front's reasons for being a singleton are not very good.
At the time we decided to make it one, the argument was that for any
given request, there could only be one front controller in play.
However, there are some use cases where this actually is a hindrance --
one in particular is if you want to *extend* it to alter or add
functionality. My plan for 2.0 is to remove the singleton.

> How do you know when it's ok to use Singletons?  It seems like
> Singletons are beneficial, when used to share a single resource,
> because they have the potential for improving performance, and
> reducing application complexity.

Remove the performance argument from this; you get good performance as
well by simply passing dependencies into other objects, as objects are
passed by reference.

Also remove the "reducing application complexity" argument, because it
actually makes maintenance harder. The more complex your application,
you only compound the complexity further by introducing singletons, as
it's harder to determine where and when values are set within the
application lifecycle. If dependencies are always passed into other
objects, you know that the caller is responsible for providing them --
making maintenance and backtracing simpler.

The only place where they make sense is when the resource in question is
truly singular in nature -- the autoloader is a good example of that.

> Let me use Michael's Factory class as an example.  Sure, you could
> probably rename the class Singleton for clarity.  In fact, the
> getInstance method could be moved inside the class of the objects
> being generated through the Factory class.
> 
> To demonstrate this, you'd create a class called Users that extends
> Zend_Db_Table and you'd give it a method called getInstance.  Doing
> this, you would effectively create a shared resource that serves as a
> link to the Users database.  Whenever you would use
> 
> $Users = new Users();
> 
> You could instead use
> 
> $Users = Users::getInstance();
> 
> That way, instead of reinstantiating an instance of Users all over the
> application, you call getInstance and re-use the same object as often
> as you'd like - giving the 7X performance boost Michael was
> mentioning.

That boost can also occur if you simply do metadata caching, per the
performance recommendations. ;) Truly, that's the single easiest way to
improve performance in Zend_Db_Table, and it has huge impact,
particularly if you instantiate multiple copies of the table within your
app.

Using a singleton for performance reasons is almost always the wrong
solution; look instead at how the objects that depend on it get the
dependency.

-- 
Matthew Weier O'Phinney
Project Lead            | [email protected]
Zend Framework          | http://framework.zend.com/

Reply via email to