Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use an abstract class instead of a private __construct() when creating a singleton in PHP?

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.)

like image 895
Peter Horne Avatar asked Mar 28 '10 13:03

Peter Horne


3 Answers

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.

like image 165
Pascal MARTIN Avatar answered Nov 15 '22 11:11

Pascal MARTIN


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.

like image 45
Daff Avatar answered Nov 15 '22 11:11

Daff


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( )  {}
   final private function __wakeup( ) {}
}

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:

  • How to remove multiple instances and just have one instance while multiple function calls in php?
  • Is there a use-case for singletons with database access in PHP?
like image 28
Gordon Avatar answered Nov 15 '22 10:11

Gordon