什么是PHP中的单例?

时间:2014-07-20 15:41:44

标签: php

对许多人来说,这个问题可能真是一个愚蠢的问题。但是,我找不到它的确切答案。

PHP中的单例类是什么?

我经历了很多教程,仍然不明白它的确切含义。 我的理解是,它不能被多次实例化。该对象将被共享。 那个的真实意义是什么?假设单例是为数据库连接实现的,这是否意味着,如果'A'访问该站点并登录。同时说'B'尝试登录,B将无法登录,直到A注销并释放该对象?

4 个答案:

答案 0 :(得分:13)

  • Singleton可以像全局变量一样使用。
  • 与普通类不同,它只能有一个该类的实例(对象)。
  • 当我们不想创建一个类的数据库连接或实用程序库的多个实例时,我们会选择单例模式。
  • Singleton确保您永远不会有多个类的实例。
  • 将构造方法设为私有以创建类Singleton。
  • 如果您不想实例化类的多个副本但只有一个,那么您只需将其置于单例模式中,您就可以调用该类的方法,并且该类只有一个副本。内存,即使你创建了它的另一个实例。
  • 如果用户只想连接到数据库,那么如果实例已经存在,则无需再次创建另一个实例,您只需使用第一个对象并进行连接。

e.g。

<?php
    class DBConn {

        private static $obj;

        private final function  __construct() {
            echo __CLASS__ . " initializes only once\n";
        }

        public static function getConn() {
            if(!isset(self::$obj)) {
                self::$obj = new DBConn();
            }
            return self::$obj;
        }
    }

    $obj1 = DBConn::getConn();
    $obj2 = DBConn::getConn();

    var_dump($obj1 == $obj2);
?>

输出:

DBConn initializes only once
bool(true)

Object1和Object2将指向同一个实例

            _______________________
           |                       |
$obj1 ---->|  Instance of DBConn   |<----- $obj2
           |_______________________| 

希望有所帮助!! :)

答案 1 :(得分:12)

单身是一种特殊的类,正如你所说,只能实例化一次。

第一点:它不是PHP相关概念,而是OOP概念。

什么&#34;只实例化一次意味着?&#34;它只是意味着如果该类的对象已经实例化,系统将返回它而不是创建新的对象。 为什么?因为,有时候,你需要一个普通的&#34;实例(全局一个)或因为实例化一个&#34; copy&#34;一个已经存在的对象是无用的。

让第一种情况考虑一个框架:在引导操作上,你需要实例化一个对象,但你可以(你必须)与框架引导程序的其他请求共享它。

对于第二种情况,让我们考虑一个只有方法而且没有成员的类(所以基本上没有内部状态)。也许您可以将它实现为静态类,但如果您想要遵循设计模式,请考虑使用AbstractFactory),您应该使用对象。因此,拥有一个只有方法的同一个对象的副本并不是必需的,也是内存浪费。

这是向我使用单身人士的两个主要原因。

答案 2 :(得分:2)

是的,您是对的:“不能多次实例化它。”当您打开数据库连接时,此概念非常有用。

假设

如果有人登录,则创建新的数据库对象。

如果有人进行了某些更新,则将创建一个新的数据库对象。

如果有人注销,则创建一个新的数据库对象。

如您所见,每次与数据库进行交互时,都会创建一个新对象并打开一个新连接。就效率而言,这是一件坏事。

这里单身人士班确实解决了这个问题。它创建一个数据库连接对象并保存它,只要需要它就返回它而不是创建一个新的对象。

class DB{
private static $_instance = null;
private $_pdo;

        private function __construct(){
            try{
                $this->_pdo = new PDO('mysql:host ='yourhost'; dbname = 'your_database','username','password);
                echo 'connected';

            }catch(PDOException $e){
                die($e->getMessage());
            }
        }
      public static function getInstance(){
          if(!isset(self::$_instance)){
              self::$_instance = new DB();
    }
    return self::$_instance; 
     }
  }

如您所见,该类将检查现有连接($ _instance属性),如果未设置,则将其返回。

答案 3 :(得分:-1)

更多参考:Is there a use-case for singletons with database access in PHP?

来自Design Patterns - PHP: The Right Way

  

在设计Web应用程序时,在概念和体系结构上通常允许访问特定类的一个且仅一个实例。单例模式使我们能够做到这一点。

<?php
class Singleton
{
    /**
     * Returns the *Singleton* instance of this class.
     *
     * @staticvar Singleton $instance The *Singleton* instances of this class.
     *
     * @return Singleton The *Singleton* instance.
     */
    public static function getInstance()
    {
        static $instance = null;
        if (null === $instance) {
            $instance = new static();
        }

        return $instance;
    }

    /**
     * Protected constructor to prevent creating a new instance of the
     * *Singleton* via the `new` operator from outside of this class.
     */
    protected function __construct()
    {
    }

    /**
     * Private clone method to prevent cloning of the instance of the
     * *Singleton* instance.
     *
     * @return void
     */
    private function __clone()
    {
    }

    /**
     * Private unserialize method to prevent unserializing of the *Singleton*
     * instance.
     *
     * @return void
     */
    private function __wakeup()
    {
    }
}

class SingletonChild extends Singleton
{
}

$obj = Singleton::getInstance();
var_dump($obj === Singleton::getInstance());             // bool(true)

$anotherObj = SingletonChild::getInstance();
var_dump($anotherObj === Singleton::getInstance());      // bool(false)

var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)
     

上面的代码使用静态变量和静态创建方法getInstance()实现单例模式。请注意以下事项:

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

当我们需要确保Web应用程序中的整个请求生命周期中只有一个类的单个实例时,单例模式很有用。当我们拥有全局对象(例如Configuration类)或共享资源(例如事件队列)时,通常会发生这种情况。

     

使用单例模式时应该小心,因为它本质上会将全局状态引入应用程序,从而降低可测试性。在大多数情况下,可以(并且应该)使用依赖注入来代替单例类。使用依赖注入意味着我们不会在应用程序的设计中引入不必要的耦合,因为使用共享或全局资源的对象不需要知道具体定义的类。

     

Singleton pattern on Wikipedia