假设我正在编写一个PHP(> = 5.0)类,它应该是一个单例。我读过的所有文档都说使类构造函数为私有,因此无法直接实例化类。
所以,如果我有这样的事情:
class SillyDB
{
private function __construct()
{
}
public static function getConnection()
{
}
}
是否有任何情况下__construct()被调用,而不是我正在做
new SillyDB()
在班级内部打电话?
为什么我允许从内部实例化SillyDB?
答案 0 :(得分:62)
__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进行数据库连接可确保您的应用程序不会同时进行大量数据库连接。
修改:根据@ emanuele-del-grande的建议添加$
答案 1 :(得分:6)
这是一个非常简单的单例,它只生成一个日期/时间字符串:
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()
{
}
}
答案 2 :(得分:4)
好的,我自己做了一些测试。
mysql_connect()
函数返回的资源(或某些其他RDBMS的其他链接)时,只要您将实例标记为私有,就不会有人对其进行子类化并篡改链接的威胁。答案 3 :(得分:2)
测试代码,Mark,让我知道你发现了什么。
编辑:此外,在这种特殊情况下,我不确定为什么你需要关注防止一个人进行子类化。如果有人可以访问您的PHP代码来对其进行子类化,那么他们也可以访问您的代码来复制它并将访问修饰符更改为他们(无论出于何种原因)找到合适的代码。
Singleton在这种情况下的实际用途是,通过使用它,您可以确保始终对给定的HTTP请求使用相同的数据库连接。它实现了这一点。其他东西(使用final
和私有构造函数)从理论角度来看是有用的,知道是否要将API质量代码分发给其他程序员更有用,但在这个特定示例的情况下,所有关键字正在做的是将字节添加到类文件的大小。
答案 4 :(得分:0)
有点挑剔:为了完整性,你可能将该类声明为最终,因为你不希望有人继承这个类并实现它自己的公共构造函数。
(如果编译器捕获到私有构造函数的覆盖,请原谅我,但我不认为它会这样做)