实现单例模式时出错

时间:2012-03-11 15:46:18

标签: php design-patterns database-design

我正在尝试实现单例模式,我收到以下错误

  

致命错误:Database :: __ construct()的访问级别必须是公共的   (在类PDO中)在第29行的/config/database.php中

<?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);

?>

5 个答案:

答案 0 :(得分:4)

通过将__construct()函数声明为像private function __construct()这样的私有函数,您实际上禁止PHP在创建对象时自动调用它。

相反,您应始终将__construct()以及其他声明方法声明为public。

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);

?>

答案 1 :(得分:3)

由于PDO的__construct()功能是公开的,因此您无法使用私有__construct()功能对其进行扩展。

所以“真正的”单身人士是不可能的 您必须设置public function __construct()

答案 2 :(得分:3)

您无法更改覆盖方法的访问级别。

您可以在Database中拥有一个PDO实例,而不是扩展PDO。 组合比继承更灵活。

答案 3 :(得分:0)

你应该

1)通过将构造函数设置为private来禁用构造函数。

2)仅通过调用静态方法创建单个PDO对象。静态方法必须返回PDO对象的实例。

在Silex或Symfony中,您必须使用“\”为类名添加前缀或使用“use \ PDO;”。这仅仅意味着这是一个全球级的。

聚苯乙烯。如果你将__constructor设置为public并使用return functino注意它不会产生任何异常或警告,但你会得到一个返回的类对象而不是return语句的实际值。

所以$ db = new Database()将返回类Database的对象。然后从那里你必须使用类方法访问你的PDO。 $ pdo = $ db-&gt; getInstance() 这不是构建合适单身人士的正确方法。

如果您有兴趣阅读有关单身人士的优缺点和一些用例,请阅读此Best practice on PHP singleton classes,您将找到有关此模式设计的更多信息。

/**
 *  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;

    }

}

答案 4 :(得分:0)

除了涉及PHP源代码的技术问题之外,在父项和子项构造函数之间具有不同访问级别的需求是完美的lecit

事实上,它已被归档为错误(#61970)。

在2017年3月的提交中,如果我没有错,开发商表示已经关闭:
http://git.php.net/?p=php-src.git;a=commitdiff;h=5324fb1f348f5bc979d9b5f13ac74177b73f9bf7

我使用7月发布的PHP 7.0.24,但我仍然认为它尚未修复。