什么是PHP中的单例?

ugmeyewa  于 2023-03-07  发布在  PHP
关注(0)|答案(4)|浏览(105)

这个问题对很多人来说可能是个很傻的问题,但是,我找不到确切的答案。
什么是PHP中的单例类?
我看了很多教程,仍然不明白它的确切含义。我理解的是,它不能被示例化超过一次。对象将被共享。这到底意味着什么?假设单例实现用于数据库连接,它是否意味着,如果'A'是访问网站和登录。同时说'B'试图登录和B将无法登录,直到A注销和释放的对象?

izkcnapc

izkcnapc1#

  • 单例变量可以像全局变量一样使用。
  • 与普通类不同,它只能有该类一个示例(对象)。
  • 当我们不想创建一个类的多个示例时,比如数据库连接或实用程序库,我们会选择单例模式。
  • 单例模式确保了你永远不会拥有一个类的多个示例。
  • 将构造方法私有化以使类成为Singleton。
  • 如果你不想示例化一个类的多个副本,而只想示例化一个,那么你只需要把它放在单例模式中,你只需要调用那个类的方法,那个类在内存中只会有它的一个副本,即使你创建了它的另一个示例。
  • 如果用户只想连接到数据库,那么不需要再创建另一个示例,如果示例已经存在,你可以只使用第一个对象,并使连接发生。

例如:

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

n6lpvg4x2#

单例类是一种特殊的类,正如您正确地指出的,它只能示例化一次。
第一点:它不是一个PHP相关的概念,而是一个OOP概念。
什么是“只示例化一次”?它只是简单地意味着,如果一个对象已经示例化,系统将返回它,而不是创建一个新的。为什么?因为,有时候,你需要一个“公共”示例(全局的)或者因为示例化一个已经存在的对象的“副本”是无用的。
让我们考虑第一种情况下的框架:在引导操作中,你需要示例化一个对象,但是你可以(你必须)与其他请求框架引导的人共享它。
对于第二种情况,让我们考虑一个只有方法而没有成员的类(因此基本上没有内部状态)。也许你可以把它实现为静态类,但是如果你想遵循设计模式,考虑AbstractFactory),你应该使用对象。所以,拥有一个只有方法的相同对象的副本是没有必要的,而且也是浪费内存的。
这是我使用singleton的两个主要原因。

vkc1a9a2

vkc1a9a23#

是的,你是对的“它不能被示例化超过一次。”这个概念是非常有用的,当你打开一个数据库连接。
假设
如果有人登录,您就创建一个新的数据库对象.
如果有人更新了某个东西,您就创建了一个新的数据库对象。
如果有人注销,则创建一个新的数据库对象。
正如你所看到的,每次与数据库交互时,都会创建一个新的对象并打开一个新的连接。这在效率方面是一件坏事。
单例类真正解决了这个问题,它创建了一个数据库连接对象并保存它,无论何时需要它都只返回它而不是创建一个新的。

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属性),如果未设置,则返回该连接。

wmomyfyw

wmomyfyw4#

更多参考:Is there a use-case for singletons with database access in PHP?
从设计模式- PHP:正确的方法:
当设计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被声明为private,以防止通过clone操作符克隆类的示例。
  • 魔术方法__wakeup被声明为private,以防止通过全局函数unserialize()对类的示例进行反序列化。
  • 在静态创建方法getInstance()中使用关键字static通过后期静态绑定创建一个新示例,这允许对示例中的类Singleton进行子类化。

当我们需要确保在Web应用程序的整个请求生命周期中只有一个类的示例时,单例模式非常有用。这通常发生在我们有全局对象(如Configuration类)或共享资源(如事件队列)时。
在使用单例模式时应该小心,因为它的本质是将全局状态引入到应用程序中,从而降低了可测试性。(并且应该)来代替单例类。使用依赖注入意味着我们没有在应用程序的设计中引入不必要的耦合,因为使用共享或全局资源的对象不需要具体定义的类的知识。
Singleton pattern on Wikipedia

相关问题