开发者

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

开发者 https://www.devze.com 2022-12-24 04:39 出处:网络
When creating a Singleton in PHP, I ensure that it cannot be instantiated by doing the following: class Singleton {

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 can开发者_如何学编程not 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.)


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.


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.


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?


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号