如何使用PHP5类创建单例类?


当前回答

你可能应该添加一个私有的__clone()方法来禁止克隆实例。

private function __clone() {}

如果您不包含此方法,则可能出现以下情况

$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;

现在$inst1 !== $inst2 -它们不再是同一个实例了。

其他回答

PHP 5.3允许通过后期静态绑定创建可继承的单例类:

class Singleton
{
    protected static $instance = null;

    protected function __construct()
    {
        //Thou shalt not construct that which is unconstructable!
    }

    protected function __clone()
    {
        //Me not like clones! Me smash clones!
    }

    public static function getInstance()
    {
        if (!isset(static::$instance)) {
            static::$instance = new static;
        }
        return static::$instance;
    }
}

这解决了一个问题,在PHP 5.3之前,任何扩展了Singleton的类都会生成父类的实例,而不是它自己的实例。

现在你可以做:

class Foobar extends Singleton {};
$foo = Foobar::getInstance();

$foo将是Foobar的一个实例而不是Singleton的一个实例。

你可能应该添加一个私有的__clone()方法来禁止克隆实例。

private function __clone() {}

如果您不包含此方法,则可能出现以下情况

$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;

现在$inst1 !== $inst2 -它们不再是同一个实例了。

不幸的是,当有多个子类时,Inwdr的答案就失效了。

下面是一个正确的可继承单例基类。

class Singleton
{
    private static $instances = array();
    protected function __construct() {}
    protected function __clone() {}
    public function __wakeup()
    {
        throw new Exception("Cannot unserialize singleton");
    }

    public static function getInstance()
    {
        $cls = get_called_class(); // late-static-bound class name
        if (!isset(self::$instances[$cls])) {
            self::$instances[$cls] = new static;
        }
        return self::$instances[$cls];
    }
}

测试代码:

class Foo extends Singleton {}
class Bar extends Singleton {}

echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";

这是在数据库类上创建单例的例子

设计模式 1)单

class Database{
  public static $instance;
  public static function getInstance(){
    if(!isset(Database::$instance)){
    Database::$instance=new Database();

     return Database::$instance;
    }

  }

  $db=Database::getInstance();
  $db2=Database::getInstance();
  $db3=Database::getInstance();

  var_dump($db);
  var_dump($db2);
  var_dump($db3);

那么输出是

  object(Database)[1]
  object(Database)[1]
  object(Database)[1]

只使用单个实例,不要创建3个实例

所有这些复杂性(“后期静态绑定”……对我来说,harumph)只是PHP对象/类模型破碎的标志。如果类对象是一级对象(参见Python),那么"$_instance"将是一个类实例变量——类对象的成员,而不是其实例的成员/属性,也与它的后代共享相反。在Smalltalk世界中,这就是“类变量”和“类实例变量”之间的区别。

在PHP中,在我看来,我们似乎需要牢记模式是编写代码的指南——我们可能会考虑Singleton模板,但试图编写从实际的“Singleton”类继承的代码对PHP来说是错误的(尽管我认为一些有进取心的人可以创建一个合适的SVN关键字)。

我将继续使用共享模板分别编写每个单例。

请注意,我绝对不会参与单身是邪恶的讨论,生命太短暂了。