假设我正在编写一个 PHP (>= 5.0) 类,它是一个单例类。我读过的所有文档都说将类构造函数设为私有,这样该类就不能直接实例化。

所以如果我有这样的东西:

class SillyDB
{
  private function __construct()
  {

  }

  public static function getConnection()
  {

  }
}

除了我正在执行的操作之外,是否有任何情况会调用 __construct()

new SillyDB() 

在类本身内部调用?

为什么我可以从 SillyDB 内部实例化 SillyDB?

有帮助吗?

解决方案

__construct() 仅当您从包含私有构造函数的类的方法中调用它时,才会调用它。因此,对于您的单例,您可能有这样的方法:

class DBConnection
{
   private static $Connection = null;

   public static function getConnection()
   {
      if(!isset(self::$Connection))
      {
         self::$Connection = new DBConnection();
      }
      return self::$Connection;
   }

   private function __construct()
   {

   }
}

$dbConnection = DBConnection::getConnection();

您能够/希望从类内部实例化该类的原因是,您可以检查以确保在任何给定时间仅存在一个实例。毕竟,这就是单例的全部意义。使用 Singleton 进行数据库连接可确保您的应用程序不会一次建立大量数据库连接。


编辑: 添加 $,按照 @emanuele-del-grande 的建议

其他提示

这是一个非常简单的单例,仅生成日期/时间字符串:

class TheDate
{
    private static $DateInstance = null;
    private $dateVal;

    public static function getDateInstance()
    {
        if(!isset(self::$DateInstance))
        {
            self::$DateInstance = new TheDate();
        }

        return self::$DateInstance;
    }

    public static function getDateVal()
    {
        return self::$DateInstance->dateVal;
    }

    private function __construct()
    {
        $this->dateVal = strftime("%Y-%m-%d %H:%M:%S");
    }
}

做这样的事情显然会让我一遍又一遍地得到相同的日期:

$date1 = TheDate::getDateInstance();
echo $date1->getDateVal() . "<br />";

$date2 = TheDate::getDateInstance();
echo $date2->getDateVal() . "<br />";

这样做不会产生任何错误:

class NewDate extends TheDate
{
    public function __construct()
    {

    }
}

好的,我自己进行了一些测试。

  • 如果你没有在子类中声明自己的构造函数,尝试实例化它会抛出致命错误,因为它试图调用超类构造函数。
  • 在数据库连接的情况下,当您可能返回(无论如何,在 PHP 中)一个 mysqli 实例或由 mysql_connect() 函数(或其他 RDBMS 的其他链接),只要将实例标记为私有,就不会存在有人对其进行子类化并篡改链接的威胁。
  • 正如我之前提到的,如果有人真的想覆盖你的行为并建立多个连接,他们也可以通过编写一个新类来做到这一点。

测试一下代码,马克,然后让我知道你发现了什么。

编辑:另外,在这种特殊情况下,我不确定为什么您需要担心防止一个人进行子类化。如果有人可以访问您的 PHP 代码来对其进行子类化,那么他们也可以访问您的代码来复制它并将访问修饰符更改为他们(无论出于何种原因)认为合适的内容。

在这种情况下,Singleton 的实际用途是,通过使用它,您可以确保对于给定的 HTTP 请求始终使用相同的数据库连接。它实现了这一点。其他东西(使用 final 从理论的角度来看,了解(和私有构造函数)很有用,并且了解是否想将 API 质量的代码分发给其他程序员更有用,但在这个特定示例的情况下,所有关键字所做的就是将字节添加到你的类文件的大小。

一点挑剔:为了完整起见,你可能会 声明该类为最终类 也是因为你不希望有人子类化这个类并实现它自己的公共构造函数。

(如果编译器捕获了私有构造函数的重写,请原谅我,但我不认为它会捕获)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top