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


当前回答

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

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

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

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

其他回答

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

设计模式 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个实例

下面是我的例子,它提供了调用as $var = new Singleton()的能力,并创建了3个变量来测试它是否创建了新对象:

class Singleton{

    private static $data;

    function __construct(){
        if ($this::$data == null){
            $this->makeSingleton();
        }
        echo "<br/>".$this::$data;
    }

    private function makeSingleton(){
        $this::$data = rand(0, 100);
    }

    public function change($new_val){
        $this::$data = $new_val;
    }

    public function printme(){
        echo "<br/>".$this::$data;
    }

}


$a = new Singleton();
$b = new Singleton();
$c = new Singleton();

$a->change(-2);
$a->printme();
$b->printme();

$d = new Singleton();
$d->printme();

支持多对象,每类一行:

这个方法将在你想要的任何类上强制单例,你所要做的就是向你想要创建单例的类中添加一个方法,这个方法会为你做这件事。

这也将对象存储在“SingleTonBase”类中,因此您可以通过递归SingleTonBase对象来调试您在系统中使用的所有对象。


创建一个名为SingletonBase.php的文件,并将其包含在脚本的根目录中!

代码是

abstract class SingletonBase
{
    private static $storage = array();

    public static function Singleton($class)
    {
        if(in_array($class,self::$storage))
        {
            return self::$storage[$class];
        }
        return self::$storage[$class] = new $class();
    }
    public static function storage()
    {
       return self::$storage;
    }
}

然后,对于任何你想要创建单例的类,只需添加这个小的单方法。

public static function Singleton()
{
    return SingletonBase::Singleton(get_class());
}

这里有一个小例子:

include 'libraries/SingletonBase.resource.php';

class Database
{
    //Add that singleton function.
    public static function Singleton()
    {
        return SingletonBase::Singleton(get_class());
    }

    public function run()
    {
        echo 'running...';
    }
}

$Database = Database::Singleton();

$Database->run();

你可以在任何类中添加这个单例函数,每个类只创建一个实例。

注意:你应该始终将__construct设为private以消除new Class()的使用;实例化。

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

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

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

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

制作单例模式的真实和现代方法是:

<?php

/**
 * Singleton Pattern.
 * 
 * Modern implementation.
 */
class Singleton
{
    /**
     * Call this method to get singleton
     */
    public static function instance()
    {
      static $instance = false;
      if( $instance === false )
      {
        // Late static binding (PHP 5.3+)
        $instance = new static();
      }

      return $instance;
    }

    /**
     * Make constructor private, so nobody can call "new Class".
     */
    private function __construct() {}

    /**
     * Make clone magic method private, so nobody can clone instance.
     */
    private function __clone() {}

    /**
     * Make sleep magic method private, so nobody can serialize instance.
     */
    private function __sleep() {}

    /**
     * Make wakeup magic method private, so nobody can unserialize instance.
     */
    private function __wakeup() {}

}

现在你可以用它。

<?php

/**
 * Database.
 *
 * Inherited from Singleton, so it's now got singleton behavior.
 */
class Database extends Singleton {

  protected $label;

  /**
   * Example of that singleton is working correctly.
   */
  public function setLabel($label)
  {
    $this->label = $label;
  }

  public function getLabel()
  {
    return $this->label;
  }

}

// create first instance
$database = Database::instance();
$database->setLabel('Abraham');
echo $database->getLabel() . PHP_EOL;

// now try to create other instance as well
$other_db = Database::instance();
echo $other_db->getLabel() . PHP_EOL; // Abraham

$other_db->setLabel('Priler');
echo $database->getLabel() . PHP_EOL; // Priler
echo $other_db->getLabel() . PHP_EOL; // Priler

正如你所看到的,这种实现更加灵活。