views:

172

answers:

4

When creating a Singleton in PHP, I ensure that it cannot be instantiated by doing the following:

class Singleton {

    private function __construct() {}
    private function __clone() {}

    public static function getInstance() {}
}

However, I realised that defining a class as 'abstract' means that it cannot be instantiated. So is there anything wrong with doing the following instead:

abstract class Singleton {

    public static function getInstance() {}
}

The second scenario allows me to write fewer lines of code which would be nice. (Not that it actually makes much of a difference.)

+2  A: 

No because then then you can't instantiate the class at all (not even in the static getInstance method). The private constructor in the singleton example just assures, that only the static getInstance method from the same class can access the constructor.

Daff
+7  A: 

When creating a singleton in PHP, declaring the __construct and __clone as private ensures that the class cannot be instanciated from the outside : it can still be instanciated from inside its declaration.

When declaring a class as abstract, it can not be instanciated at all ; not even from inside its declaration.

This means your solution would not work : in the second case, your getInstance() method will not be able to instanciate the class -- while it can do so in the first case.

Pascal MARTIN
A: 

It could work if your Singleton::getInstance() is supposed to return an instance of a different class.

abstract class Singleton {
  public static function getInstance() {
    static $instance = null;
    if ( is_null($instance) ) {
      $instance = new StdClass; // a different class than 'abstract class Singleton'
      $instance->x = time();
    }
    return $instance;
  }
}

$obj = Singleton::getInstance();

But I'd find that confusing. A bit like misusing abstract to combine the complexity of an abstract factory with the restraints of a singleton.

VolkerK
A: 

No, you cannot use an abstract class instead of a private __construct() when creating a singleton. But if your intention is to create an Abstract Singleton from which to extend from, you can do so like this:

abstract class Singleton
{
   private static $_instances;
   public static function getInstance()
   {
      $className = get_called_class(); // As of PHP 5.3
      if(! isset(self::$_instances[$className] )) {
         self::$_instances[$className] = new $className();
      }
      return self::$_instances[$className];
   }
   protected function __construct( ) {}
   final private function __clone( ) {}
}

You can then extend from Singleton like this:

class Foo extends Singleton {

    protected $_foo = 1;
    public function setFoo($i) { $this->_foo = $i; }
    public function getFoo() { return $this->_foo; }
}

and

class Bar extends Singleton {

    protected $_foo = 1;
    public function setFoo($i) { $this->_foo = $i; }
    public function getFoo() { return $this->_foo; }
}

and manipulating:

$foo1 = Foo::getInstance();
$foo1->setFoo(5);

$foo2 = Foo::getInstance();
var_dump($foo2); 

$bar1 = Bar::getInstance();
var_dump($bar1);

echo new ReflectionObject($foo2);
echo new ReflectionObject($bar1);

However, keep in mind that Singletons are very hard to unit-test and should be avoided if possible. See my answer here for some background:

Gordon
I wasn't attempting to create an abstract singleton class, but I'm sure someone will find this useful so thanks. I'm aware of the issues of Singletons and I prefer to use DI or static registries and factories; this question was to satisfy my curiosity! However, I clearly should have tested out my idea first as one can tell from the other comments.
Pheter