我正在尝试实现singleton模式,并得到以下错误
致命错误:对数据库的访问级别:__construct()必须是公共的(如PDO类)在/config/database.php中的第29行
<?php
class Database extends PDO
{
private static $instance;
private function __construct()
{
return parent::__construct(
"mysql:host=localhost;dbname=live",
"root",
"root"
);
}
public function getInstance() {
if(self::$instance === null) {
self::$instance = new Database();
}
return self::$instance;
}
public function __clone()
{
die(__CLASS__ . ' class cant be instantiated. Please use the method called getInstance.');
}
}
$mySingleton = Database::getInstance();
var_dump($mySingleton);
?>
通过像private function __construct()
一样将__construct()函数声明为私有函数,实际上是禁止PHP在创建对象时自动调用它。
相反,您应该始终将__construct()以及其他魔术方法声明为公共方法。
public function __construct()
{
// Now PHP can access me
}
就使Database
类遵循单例模式而言,扩展一个不遵循的类(即PDO)是没有意义的。相反,做一些类似的事情:
<?php
class Database
{
private static $instance;
public function __construct()
{
// Check to see if static PDO instance
// has already been created, so we create only one (singleton)
if(!self::$instance)
{
self::$instance = new PDO(
"mysql:host=localhost;dbname=live",
"root",
"root"
);
}
}
public function getInstance() {
if(self::$instance === null) {
self::__construct();
}
return self::$instance;
}
public function __clone()
{
die(__CLASS__ . ' class cant be instantiated. Please use the method called getInstance.');
}
}
$mySingleton = Database::getInstance();
var_dump($mySingleton);
?>
您不能更改覆盖方法的访问级别。
您可以在Database
中拥有一个PDO实例,而不是扩展PDO。组合比继承更灵活。
由于PDO的__construct()
函数是公共的,因此无法使用专用__construct()
函数对其进行扩展。
因此,"真正的"单例是不可能的
您必须设置public function __construct()
。
除了涉及PHP源代码的技术困难外,父构造函数和子构造函数之间需要不同的访问级别是完美的选择。
事实上,它已经被归档为一个bug(#61970)。
在2017年3月做出的这一承诺中,如果我没有错的话,开发商表示它已经关闭:
http://git.php.net/?p=php-src.git;a=commitdiff;h=5324fb1f348f5bc979d9b5f13ac74177b73f9bf7
我使用7月份发布的PHP 7.0.24,但我仍然看到它还没有修复
您应该
1) 通过将构造函数设置为private来禁用构造函数。
2) 仅通过调用静态方法来创建单个PDO对象。静态方法必须返回PDO对象的实例。
在Silex或Symfony中,您必须在类名前面加上"''"或使用"use''PDO;"。这意味着这是一个全球性的阶层。
Ps。如果将__constructor设置为public并使用return functino,请注意,它不会生成任何异常或警告,但会返回一个类对象,而不是return语句的实际值。
所以$db=new Database()将返回Database类的对象。然后,您将不得不使用类方法访问您的PDO$pdo=$db->getInstance()这不是构建合适的singleton的正确方法。
如果您有兴趣阅读更多关于singletons的优点和缺点以及一些用例,请阅读PHP singleton类的最佳实践,您将找到有关此模式设计的更多信息。
/**
* Singleton pattern
*/
class Database
{
/**
* holds the only PDO instance
*/
private static $_instance;
/**
* private __constructor not accesible
*/
private function __construct()
{
self::$instance = new PDO(
"mysql:host=localhost;dbname=live",
"root",
"root"
);
}
/**
* clone will not duplicate object
*/
public function __clone()
{
die(__CLASS__ . ' class cant be instantiated. Please use the method called getInstance.');
}
/**
* the only public function to access or create PDO object
*/
public static function getInstance()
{
if(!self::$_instance instanceof PDO){
new self;
}
return self::$_instance;
}
}