Why people use singletons in their PHP framework

2019-03-19 01:23发布

问题:

Ok guys I am struggling to understand why there is a need of singleton.

Let's make a real example: I have a framework for a my CMS
I need to have a class that logs some information (let's stick on PHP).

Example:

class Logger{
   private $logs = array();

   public function add($log) {
      $this->logs[]=$log;
   }      
}

Now of course this helper object must be unique for the entry life of a page request of my CMS.
And to solve this we would make it a singleton (declaring private the constructor etc.)

But Why in the hell a class like that isn't entirerly static? This would solve the need of the singleton pattern (that's considered bad pratice) Example:

class Logger {
    private static $logs = array();

    public static function add($log) {
        self::$logs[]=$log;
    }
}

By making this helper entirely static, when we need to add a log somewhere in our application we just need to call it statically like: Logger::add('log 1'); vs a singleton call like: Logger::getInstance()->add('log 1');

Hope someone makes it easy to understand for me why use singleton over static class in PHP.

Edit

This is a pretty nice lecture on the singleton vs static class for who is interested, thanks to @James. (Note it doesn't address my question)

回答1:

Many reasons.

Static methods are basically global functions that can be called from any scope, which lends itself to hard to track bugs. You might as well not use a class at all.

Since you cannot have a __construct method, you may have to put an init static method somewhere. Now people in their code are unsure if the init method has been called previously. Do they call it again? Do they have to search the codebase for this call? What if init was somewhere, but then gets removed, or breaks? Many places in your code now rely on the place that calls the init method.

Static methods are notoriously hard to unit test with many unit testing frameworks.

There are many more reasons, but it's hard to list them all.

Singletons aren't really needed either if you are using DI.

A side note. DI allows for your classes not to rely on each other, but rather on interfaces. Since their relationships are not cemented, it is easier to change your application at a later time, and one class breaking will not break both classes.

There are some instances where single state classes are viable, for instance if none of your methods rely on other methods (basically none of the methods change the state of the class).



回答2:

I use singletons, so I can tell you exactly why I do it instead of a static function.

The defining characteristic of a singleton is that it is a class that has just one instance. It is easy to see the "just one instance" clause and forget to see the "it is a class" clause. It is, after all, a normal class object with all the advantages that that brings. Principly, it has its own state and it can have private functions (methods). Static functions have to do both of these in more limited or awkward ways.

That said, the two complement each other: a static function can be leveraged to return a singleton on the same class. That's what I do in the singleton I use the most often: a database handler.

Now, many programmers are taught that "singletons are bad, mm'kay?" but overlook the rider that things like are usually only bad when overused. Just like a master carver, an experienced programmer has a lot of tools at his disposal and many will not get a lot of use. My database handler is ideal as a singleton, but it's the only one I routinely use. For a logging class, I usually use static methods.



回答3:

Singletons allow you to override behavior. Logger::add('1') for example can log to different devices only if the Logger class knows how. Logger::getLogger()->add('1') can do different things depending on what subtype of Logger getLogger() returns. Sure you can do everything within the logger class, but often you then end up implementing the singleton inside the static class.



回答4:

If you have a static method that opens a file, writes out and closes it, you may end up with two calls trying to open the same file at the same time, as a static method doesn't guarantee there is one instance.

But, if you use a singleton, then all calls use the same file handler, so you are always only having one write at a time to this file.

You may end up wanting to queue up the write requests, in case there are several, if you don't want them to fail, or you have to synchronize in other ways, but all calls will use the same instance.

UPDATE:

This may be helpful, a comparison on static versus singleton, in PHP.

http://moisadoru.wordpress.com/2010/03/02/static-call-versus-singleton-call-in-php/



回答5:

As leblonk mentioned, you can't override static classes, which makes unit testing very difficult. With a singleton, you can instantiate a "mock" object instead of the actual class. No code changes needed.

Static classes can have namespace conflicts. You can't load 2 static classes of the same name, but you can load 2 different versions of a singleton and instantiate them under the same name. I've done this when I needed to test new versions of classes. I instantiate a different version of the class, but don't need to change the code that references that class.

I often mix singletons and static. For example, I use a database class that ensures there is only 1 connection to each master (static) and slave (singleton). Each instance of the db class can connect to a different slave, if a connection to the same slave is requested, the singleton object is returned. The master connection is a static object instantiated inside each slave singleton, so only 1 master connection exists across all db instantiated objects.