在PHP5中创建Singleton设计模式


204

一个人如何使用PHP5类创建Singleton类?



1
@Andrew不要实例化连接到数据库的第二个实例。将该实例传递到需要的地方。单身人士的需要是代码气味。有关更多信息,请访问gooh.posterous.com/singletons-in-php
Gordon

3
@安德鲁·姆姆凯(Andrew Mmmmkay)。没有冒犯,但我建议您在继续讨论之前获得一本有关软件质量的书。单例不简化但会使正常的维护和开发复杂化。实际上,这是另一回事:单元测试首先简化并支持开发。
Gordon

3
@Andrew:现在假设您只需要一个数据库连接。当您的需求发生变化并且您实际上需要与2个数据库服务器通信时会发生什么?更不用说您是否不能相信您的团队做正确的事,创建一个单身人士对您毫无帮助。从一开始就做正确的事情,并拥有一支可以信任的团队,并且会没事的。
ircmaxell 2011年

4
仅仅因为Singleton被过度使用,并不意味着它应该成为一个可避免的错误模式。不要讨厌辛格尔顿。有时,这是对某些问题的完美解决方案。最好开始争论为什么我们不应该使用它,而不仅仅是情感上要对其进行降级。
吉尔斯·莱斯雷

Answers:


268
/**
 * Singleton class
 *
 */
final class UserFactory
{
    /**
     * Call this method to get singleton
     *
     * @return UserFactory
     */
    public static function Instance()
    {
        static $inst = null;
        if ($inst === null) {
            $inst = new UserFactory();
        }
        return $inst;
    }

    /**
     * Private ctor so nobody else can instantiate it
     *
     */
    private function __construct()
    {

    }
}

使用方法:

$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();

$fact == $fact2;

但:

$fact = new UserFactory()

引发错误。

请参阅http://php.net/manual/zh-CN/language.variables.scope.php#language.variables.scope.static了解静态变量范围以及为什么设置static $inst = null;有效。


59
比较两个实例,您应该使用===而不是==。如果$ fact1和$ fact2属于同一类,则==将返回true,但仅当它们都是同一对象的相同实例时,===才返回true。
Keith Twombley,

10
克隆方法也应该是私有的
Alex Petrov

22
每次调用Instance()时,此方法都不会将UserFactory的实例重置为null吗?在java中,$ inst变量将是一个私有的静态属性,不应一遍又一遍地重置它,否则您最好不要将其设置为单例。
Rudy Garcia 2013年

8
这里有一个很好的写了,为什么,以及如何声明变量作为函数作品的作者的静态打算:php.net/manual/en/...
hereswhatidid

10
您应该使用$ inst = new self(); 不是$ inst = new UserFactory(); 给以后遇到的任何人。+1用于使用内置的PHP方法。
Ligemer

119

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

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的实例。


1
在php 5.3中,后期静态绑定确实是一件非常好的事情。太糟糕了,我仍然无法使用它。
AntonioCS

4
来自@ggsonic :"subclass should own its own static var. check this: echo get_class(Foobar::getInstance());echo get_class(Singleton::getInstance());"
布罗克·亚当斯

4
这根本行不通,恰好是Foobar是您建造的第一堂课?
克里斯·KL

1
仍然可以克隆..“” $ a = Singleton :: getInstance(); $ b = unserialize(serialize($ a)); $ a!== $ b;“
bortunac 2012年

15
如果有多个子类,则此方法不起作用!$instance驻留在Singleton中,而不是子类中。在实例化某些子类之后,getInstance()将为所有子类返回该实例。
mpartel

116

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

这是一个正确的可继承的Singleton基类。

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
到目前为止,这最接近正确的Singleton实现。您还应该考虑抛出__wakeup()方法以防止反序列化。
罗伯特·罗斯曼

实际上,您必须抛出Exception或手动引发错误-将函数声明为protected / private只会引发E_WARNING,表明它无法访问该方法,但否则将继续。
罗伯特·罗斯曼

谢谢。我通常将所有警告等都转换为异常,因此我在测试:P
mpartel

这是我发现的唯一可以正确处理多个子类的解决方案。谢谢!
鲍勃·丹克特

36

制作Singleton模式的一种真实且现代的方法是:

<?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

如您所见,这种实现更加灵活。


4
这是此线程中有关Singleton模式的最明确答案。谢谢。
古斯

我已经实现了这种方法,并且可以像预期的那样工作:第二个实例变为null。但是,我也不需要扩展具体的课程。我刚刚在该具体类的构造函数中实现了Singleton :: instance()。
snaphuman

instance功能$instance应该是null没有false
Mifas

是的,但这不是功能,而是方法。
亚伯拉罕·图加洛夫'17

26

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

private function __clone() {}

如果您不包括此方法,则可以进行以下操作

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

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


11
<?php
/**
 * Singleton patter in php
 **/
trait SingletonTrait {
   protected static $inst = null;

  /**
   * call this method to get instance
   **/
   public static function getInstance(){
      if (static::$inst === null){
         static::$inst = new static();
      }
      return static::$inst;
  }

  /**
   * protected to prevent clonning 
   **/
  protected function __clone(){
  }

  /**
   * protected so no one else can instance it 
   **/
  protected function __construct(){
  }
}

使用:

/**
 *  example of class definitions using SingletonTrait
 */
class DBFactory {
  /**
   * we are adding the trait here 
   **/
   use SingletonTrait;

  /**
   * This class will have a single db connection as an example
   **/
  protected $db;


 /**
  * as an example we will create a PDO connection
  **/
  protected function __construct(){
    $this->db = 
        new PDO('mysql:dbname=foodb;port=3305;host=127.0.0.1','foouser','foopass');
  }
}
class DBFactoryChild extends DBFactory {
  /**
   * we repeating the inst so that it will differentiate it
   * from UserFactory singleton
   **/
   protected static $inst = null;
}


/**
 * example of instanciating the classes
 */
$uf0 = DBFactoryChild::getInstance();
var_dump($uf0);
$uf1 = DBFactory::getInstance();
var_dump($uf1);
echo $uf0 === $uf1;

重新放置:

object(DBFactoryChild)#1 (0) {
}
object(DBFactory)#2 (0) {
}

如果您使用的是PHP 5.4:trait是它的一个选择,那么您不必浪费继承层次结构即可拥有Singleton模式

并且还请注意,如果不添加以下代码行,则是使用特征还是扩展Singleton类的一个松散结局是创建子类的Singleton

   protected static $inst = null;

在儿童班

意外的结果将是:

object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}

10
protected  static $_instance;

public static function getInstance()
{
    if(is_null(self::$_instance))
    {
        self::$_instance = new self();
    }
    return self::$_instance;
}

该代码可以适用于任何类别,而无需关心其类别名称。


8

支持多个对象,每个类1行:

此方法将对您希望的任何类强制执行单例,而您要做的就是向希望创建单例的类添加1个方法,这将为您完成。

这还将对象存储在“ 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();

您可以只在您拥有的任何类中添加此单例函数,并且每个类仅创建1个实例。

注意:您应始终将__construct设为私有,以消除对new Class()的使用。实例化。


5
class Database{

        //variable to hold db connection
        private $db;
        //note we used static variable,beacuse an instance cannot be used to refer this
        public static $instance;

        //note constructor is private so that classcannot be instantiated
        private function __construct(){
          //code connect to database  

         }     

         //to prevent loop hole in PHP so that the class cannot be cloned
        private function __clone() {}

        //used static function so that, this can be called from other classes
        public static function getInstance(){

            if( !(self::$instance instanceof self) ){
                self::$instance = new self();           
            }
             return self::$instance;
        }


        public function query($sql){
            //code to run the query
        }

    }


Access the method getInstance using
$db = Singleton::getInstance();
$db->query();

5

您实际上不需要使用Singleton模式,因为它被视为反模式。基本上,有很多理由根本不执行此模式。首先阅读本节:PHP单例类的最佳实践

如果毕竟您仍然认为需要使用Singleton模式,那么我们可以编写一个类,该类将通过扩展SingletonClassVendor抽象类来获得Singleton功能。

这就是我用来解决这个问题的方法。

<?php
namespace wl;


/**
 * @author DevWL
 * @dosc allows only one instance for each extending class.
 * it acts a litle bit as registry from the SingletonClassVendor abstract class point of view
 * but it provides a valid singleton behaviour for its children classes
 * Be aware, the singleton pattern is consider to be an anti-pattern
 * mostly because it can be hard to debug and it comes with some limitations.
 * In most cases you do not need to use singleton pattern
 * so take a longer moment to think about it before you use it.
 */
abstract class SingletonClassVendor
{
    /**
     *  holds an single instance of the child class
     *
     *  @var array of objects
     */
    protected static $instance = [];

    /**
     *  @desc provides a single slot to hold an instance interchanble between all child classes.
     *  @return object
     */
    public static final function getInstance(){
        $class = get_called_class(); // or get_class(new static());
        if(!isset(self::$instance[$class]) || !self::$instance[$class] instanceof $class){
            self::$instance[$class] = new static(); // create and instance of child class which extends Singleton super class
            echo "new ". $class . PHP_EOL; // remove this line after testing
            return  self::$instance[$class]; // remove this line after testing
        }
        echo "old ". $class . PHP_EOL; // remove this line after testing
        return static::$instance[$class];
    }

    /**
     * Make constructor abstract to force protected implementation of the __constructor() method, so that nobody can call directly "new Class()".
     */
    abstract protected 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() {}

}

使用示例:

/**
 * EXAMPLE
 */

/**
 *  @example 1 - Database class by extending SingletonClassVendor abstract class becomes fully functional singleton
 *  __constructor must be set to protected becaouse: 
 *   1 to allow instansiation from parent class 
 *   2 to prevent direct instanciation of object with "new" keword.
 *   3 to meet requierments of SingletonClassVendor abstract class
 */
class Database extends SingletonClassVendor
{
    public $type = "SomeClass";
    protected function __construct(){
        echo "DDDDDDDDD". PHP_EOL; // remove this line after testing
    }
}


/**
 *  @example 2 - Config ...
 */
class Config extends SingletonClassVendor
{
    public $name = "Config";
    protected function __construct(){
        echo "CCCCCCCCCC" . PHP_EOL; // remove this line after testing
    }
}

只是为了证明它能按预期工作:

/**
 *  TESTING
 */
$bd1 = Database::getInstance(); // new
$bd2 = Database::getInstance(); // old
$bd3 = Config::getInstance(); // new
$bd4 = Config::getInstance(); // old
$bd5 = Config::getInstance(); // old
$bd6 = Database::getInstance(); // old
$bd7 = Database::getInstance(); // old
$bd8 = Config::getInstance(); // old

echo PHP_EOL."COMPARE ALL DATABASE INSTANCES".PHP_EOL;
var_dump($bd1);
echo '$bd1 === $bd2' . ($bd1 === $bd2)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd2 === $bd6' . ($bd2 === $bd6)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd6 === $bd7' . ($bd6 === $bd7)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE

echo PHP_EOL;

echo PHP_EOL."COMPARE ALL CONFIG INSTANCES". PHP_EOL;
var_dump($bd3);
echo '$bd3 === $bd4' . ($bd3 === $bd4)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd4 === $bd5' . ($bd4 === $bd5)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd5 === $bd8' . ($bd5 === $bd8)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE

在阅读更多赞成的答案时,我想到了类似的东西。幸运的是它已经在这里了:)
hatef

3

对我而言,所有这些复杂性(“后期静态绑定” ...拙劣的理解)只是PHP损坏的对象/类模型的标志。如果类对象是一流的对象(请参阅Python),则“ $ _instance”将是一个类实例变量-类对象的成员,与其实例的成员/属性相对,也与共享的相对由其后代。在Smalltalk世界中,这是“类变量”和“类实例变量”之间的区别。

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

我将继续使用共享模板分别对每个单例进行编码。

请注意,我绝对不参加单例讨论,生活太短了。


当您查看日益复杂的PHP语言时,您的言论是正确的。似乎添加了太多新的关键字,无法解决太多不同编码范例中太多不同设计漏洞。更糟糕的是,由于更改率很高,并且版本在主机和开发平台之间存在偏差,因此今天的“解决方案”(如@Eric Anderson的回答[ stackoverflow.com/a/23998306/3696363]中的特征)不起作用在可能运行“稳定”版本而不是“最新,最好”版本的生产系统上。
Eliyahu Skoczylas

2

我知道这可能会引起不必要的火焰战争,但是我可以看到您可能想要多个数据库连接,因此我要承认单身人士可能不是最好的解决方案……不过,我发现单例模式的其他用途非常有用。

这是一个例子:我决定推出自己的MVC和模板引擎,因为我想要真正轻巧的东西。但是,我要显示的数据包含许多特殊的数学字符(例如≥和μ)以及您所拥有的内容...数据以实际的UTF-8字符存储在我的数据库中,而不是预先进行HTML编码,因为除了HTML之外,我的应用程序还可以提供其他格式,例如PDF和CSV。HTML格式的适当位置是在模板内部(如果需要,则为“视图”),该模板负责呈现该页面部分(摘要)。我想将它们转换为适当的HTML实体,但是PHP的get_html_translation_table()函数并不是非常快。一次取回数据并将其存储为数组,使所有人都可以使用它,这更有意义。这里' 我将样品敲在一起测试速度。大概,不管您使用的其他方法(获取实例之后)是否是静态的,这都将起作用。

class EncodeHTMLEntities {

    private static $instance = null;//stores the instance of self
    private $r = null;//array of chars elligalbe for replacement

    private function __clone(){
    }//disable cloning, no reason to clone

    private function __construct()
    {
        $allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
        $specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
        $this->r = array_diff($allEntities, $specialEntities);
    }

    public static function replace($string)
    {
        if(!(self::$instance instanceof self) ){
            self::$instance = new self();
        }
        return strtr($string, self::$instance->r);
    }
}
//test one million encodings of a string
$start = microtime(true);
for($x=0; $x<1000000; $x++){
    $dump = EncodeHTMLEntities::replace("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)");
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds using singleton\n";
//now repeat the same without using singleton
$start = microtime(true);
for($x=0; $x<1000000; $x++){
    $allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
    $specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
    $r = array_diff($allEntities, $specialEntities);
    $dump = strtr("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)", $r);
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds without using singleton";

基本上,我看到了这样的典型结果:

php test.php
运行时间:27.842966794968秒(使用单例)
运行时间:237.78191494942秒,不使用单例

因此,尽管我当然不是专家,但我没有看到一种更便捷,更可靠的方法来减少对某种数据的缓慢调用的开销,同时又使其变得超级简单(只需一行代码即可完成所需的工作)。当然,我的示例只有一种有用的方法,因此它并不比全局定义的函数好,但是一旦您拥有两种方法,就将它们分组在一起,对吗?我离基地远吗?

另外,我更喜欢实际执行某些操作的示例,因为有时当示例中包含诸如“ //在此处做一些有用的事情”之类的语句时,很难看到它,我在搜索教程时一直会看到这些语句。

无论如何,我很喜欢关于为什么将单例用于这种类型的事情有害(或过于复杂)的任何反馈或评论。


1

本文相当广泛地涵盖了主题:http : //www.phptherightway.com/pages/Design-Patterns.html#singleton

请注意以下几点:

  • 构造函数__construct()声明为protected防止通过new运算符在类外部创建新实例。
  • __clone()声明了magic方法,private以防止通过clone运算符克隆类的实例。
  • __wakeup()声明了magic方法,private以防止通过全局函数对类的实例进行反序列化 unserialize()
  • 通过getInstance()使用关键字的静态创建方法中的后期静态绑定来创建新实例static。这允许class Singleton示例中的子类化。

1

我写了很久很久的想法,想在这里分享

class SingletonDesignPattern {

    //just for demo there will be only one instance
    private static $instanceCount =0;

    //create the private instance variable
    private static $myInstance=null;

    //make constructor private so no one create object using new Keyword
    private function  __construct(){}

    //no one clone the object
    private function  __clone(){}

    //avoid serialazation
    public function __wakeup(){}

    //ony one way to create  object
    public static  function  getInstance(){

        if(self::$myInstance==null){
            self::$myInstance=new SingletonDesignPattern();
            self::$instanceCount++;
        }
        return self::$myInstance;
    }

    public static function getInstanceCount(){
        return self::$instanceCount;
    }

}

//now lets play with singleton design pattern

$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();

echo "number of instances: ".SingletonDesignPattern::getInstanceCount();

0

我同意第一个答案,但我还要声明该类为final类,以便在扩展单例违反单例模式时无法扩展。另外,实例变量应该是私有的,这样就不能直接访问它。还要将__clone方法设为私有,以便您无法克隆单例对象。

以下是一些示例代码。

/**
 * Singleton class
 *
 */
final class UserFactory
{
    private static $_instance = null;

    /**
     * Private constructor
     *
     */
    private function __construct() {}

    /**
     * Private clone method
     *
     */
     private function __clone() {}

    /**
     * Call this method to get singleton
     *
     * @return UserFactory
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new UserFactory();
        }
        return self::$_instance;
    }
}

用法示例

$user_factory = UserFactory::getInstance();

这会阻止您执行操作(这会违反单例模式。

你不能做这个!

$user_factory = UserFactory::$_instance;

class SecondUserFactory extends UserFactory { }

0

这应该是Singleton的正确方法。

class Singleton {

    private static $instance;
    private $count = 0;

    protected function __construct(){

    }

    public static function singleton(){

        if (!isset(self::$instance)) {

            self::$instance = new Singleton;

        }

        return self::$instance;

    }

    public function increment()
    {
        return $this->count++;
    }

    protected function __clone(){

    }

    protected function __wakeup(){

    }

} 

0

我喜欢使用@trait的@ jose-segura方法,但不喜欢需要在子类上定义静态变量。下面是一种解决方案,它通过将静态局部变量中的实例缓存到按类名索引的工厂方法来避免这种情况:

<?php
trait Singleton {

  # Single point of entry for creating a new instance. For a given
  # class always returns the same instance.
  public static function instance(){
    static $instances = array();
    $class = get_called_class();
    if( !isset($instances[$class]) ) $instances[$class] = new $class();
    return $instances[$class];
  }

  # Kill traditional methods of creating new instances
  protected function __clone() {}
  protected function __construct() {}
}

用法与@ jose-segura相同,仅在子类中不需要静态变量。


0

检查是否有任何现有数据库实例的数据库类将返回先前的实例。

   class Database {  
        public static $instance;  
         public static function getInstance(){  
            if(!isset(Database::$instance) ) {  
                Database::$instance = new Database();  
            }  
           return Database::$instance;  
         }  
         private function __cunstruct() {  
           /* private and cant create multiple objects */  
         }  
         public function getQuery(){  
            return "Test Query Data";  
         }  
    }  
    $dbObj = Database::getInstance();  
    $dbObj2 = Database::getInstance();  
    var_dump($dbObj);  
    var_dump($dbObj2);  


/* 
After execution you will get following output: 

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

*/  

参考http://www.phptechi.com/php-singleton-design-patterns-example.html


0

这是在Database类上创建单例的示例

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


0

快速示例:

final class Singleton
{
    private static $instance = null;

    private function __construct(){}

    private function __clone(){}

    private function __wakeup(){}

    public static function get_instance()
    {
        if ( static::$instance === null ) {
            static::$instance = new static();
        }
        return static::$instance;
    }
}

希望对您有所帮助。


-4

这是我的示例,该示例提供了调用$ 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();

5
除了不是单例。您可以创建类Singleton的多个实例。
Andrew Moore

我认为毕竟是这样,因为无论哪个实例影响Singleton类,更改都适用于Singleton的所有实例。我在上面又添加了两个功能。现在,让我们尝试在一个实例中修改数据,然后检查其他实例。那么,是不是Singleton,如果不是,那是什么不对?
bboydev

5
单例是仅允许其自身一个实例的类。通过创建多个实例,您将使该原理无效。
Andrew Moore
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.