在PHP5类中,什么时候调用私有构造函数?

时间:2020-03-05 18:42:50  来源:igfitidea点击:

假设我正在写一个旨在成为单例的PHP(> = 5.0)类。我阅读的所有文档都说要使类构造函数私有,所以不能直接实例化该类。

所以,如果我有这样的事情:

class SillyDB
{
  private function __construct()
  {

  }

  public static function getConnection()
  {

  }
}

除了我在做__construct()之外,是否还有其他情况?

new SillyDB()

在类本身内部调用?

为何我完全允许从自身内部实例化SillyDB?

解决方案

回答

仅当我们从包含私有构造函数的类的方法中调用__construct()时,才会调用它。因此,对于Singleton,我们可能具有如下方法:

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用于数据库连接可确保应用程序一次不会建立大量的DB连接。

回答

一个小小的建议:为完整起见,我们可能也将类声明为final,因为我们不希望有人继承该类并实现其自己的公共构造函数。

(如果编译器捕获了私有构造函数的重载,请原谅我,但我不认为这样做)

回答

测试代码,Mark,让我知道我们发现了什么。

编辑:而且,在这种特殊情况下,我不确定为什么我们需要关注防止某个人继承。如果某人有权访问PHP代码以对其进行子类化,那么他们也有权访问代码以对其进行复制并将访问修饰符更改为他们(出于任何原因)认为合适的内容。

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

回答

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

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的其他链接),只要我们将实例标记为私有,不存在有人将其继承和篡改链接的威胁。
  • 正如我之前提到的,如果有人真的想重写行为并建立多个连接,那么他们也可以通过编写一个新类来做到这一点。