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

发布于 2024-08-27 05:49:38 字数 412 浏览 6 评论 0原文

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

class Singleton {

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

    public static function getInstance() {}
}

但是,我意识到将类定义为“抽象”意味着它无法实例化。那么,执行以下操作有什么问题吗:

abstract class Singleton {

    public static function getInstance() {}
}

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

忆梦 2024-09-03 05:49:38

在 PHP 中创建单例时,将 __construct 和 __clone 声明为私有可确保该类无法从外部实例化:它仍然可以从其声明中实例化。

当将一个类声明为抽象时,它根本无法实例化;甚至从其声明中也没有。

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

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.

终陌 2024-09-03 05:49:38

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

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.

謸气贵蔟 2024-09-03 05:49:38

不可以,创建单例时不能使用抽象类来代替私有 __construct()。但是,如果您的目的是创建一个从中进行扩展的抽象单例,您可以这样做:

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; }
}

class Bar 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);

但是,请记住单例很难进行单元测试并应尽可能避免。请参阅我的回答以了解一些背景:

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:

安静 2024-09-03 05:49:38

如果您的 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();

但我会发现这令人困惑。有点像滥用抽象来将抽象工厂的复杂性与单例的限制结合起来。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文