在PHP中创建单例时,我可以使用抽象类而不是私有的_构造()吗?

在PHP中创建单例时,我可以使用抽象类而不是私有的_构造()吗?,php,singleton,abstract-class,Php,Singleton,Abstract Class,在PHP中创建单例时,我确保不能通过执行以下操作来实例化它: class Singleton { private function __construct() {} private function __clone() {} public static function getInstance() {} } 然而,我意识到将类定义为“抽象”意味着它不能被实例化。那么,改为执行以下操作是否有任何错误: abstract class Singleton { p

在PHP中创建单例时,我确保不能通过执行以下操作来实例化它:

class Singleton {

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

    public static function getInstance() {}
}
然而,我意识到将类定义为“抽象”意味着它不能被实例化。那么,改为执行以下操作是否有任何错误:

abstract class Singleton {

    public static function getInstance() {}
}

第二种情况允许我编写更少的代码行,这会很好。(并不是说它实际上有多大区别。)

不,因为这样您就根本无法实例化该类(即使在静态getInstance方法中也不行)。singleton示例中的私有构造函数只是确保只有来自同一类的静态getInstance方法才能访问构造函数。

在PHP中创建singleton时,将
\uu构造
\uu克隆
声明为私有可确保类不能从外部实例化:它仍然可以从其声明内部实例化

将类声明为
抽象时,它根本不能实例化;甚至从它的声明里面也没有


这意味着您的解决方案将不起作用:在第二种情况下,您的
getInstance()
方法将无法实例化该类,而在第一种情况下它可以这样做。

如果您的
Singleton::getInstance()
应该返回另一个类的实例,那么它可能会起作用

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();

但我会觉得很困惑。有点像误用
abstract
将抽象工厂的复杂性与单例约束结合起来。

不,在创建单例时,不能使用抽象类而不是私有构造()。但是,如果您打算创建一个抽象的单例,从中进行扩展,您可以这样做:

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( ) {}
}
class Foo extends Singleton {

    protected $_foo = 1;
    public function setFoo($i) { $this->_foo = $i; }
    public function getFoo() { return $this->_foo; }
}
然后,您可以从Singleton进行如下扩展:

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( ) {}
}
class Foo extends Singleton {

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

和操纵:

$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);
但是,请记住,单例测试很难进行单元测试,如果可能的话应该避免。有关一些背景信息,请参见我的回答:


我并没有试图创建一个抽象的单例类,但我相信有人会发现这很有用,谢谢。我知道单例的问题,我更喜欢使用DI或静态注册表和工厂;这个问题是为了满足我的好奇心!然而,我显然应该先测试一下我的想法,从其他评论中可以看出。+1是一个完全可用的例子。很酷,不知道PHP中的抽象,它是在PHP5中引入的,这些家伙不会浪费时间,总是添加新的很酷的特性。谢谢,和+1发布了这么有趣的问题。@Marco PHP5从7年前的2004年7月开始发布。这不是什么新功能。