Ошибка в реализации одноэлементного шаблона - PullRequest
4 голосов
/ 11 марта 2012

Я пытаюсь реализовать шаблон синглтона и получаю следующую ошибку

Неустранимая ошибка: уровень доступа к базе данных :: __ 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);

?>

Ответы [ 5 ]

4 голосов
/ 11 марта 2012

Объявляя функцию __construct () закрытой, как private function __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);

?>
3 голосов
/ 11 марта 2012

Вы не можете изменить уровень доступа для метода переопределения.

Вместо расширения PDO, вы можете просто иметь экземпляр PDO в Database.Композиция более гибкая, чем наследование.

3 голосов
/ 11 марта 2012

Поскольку функция PDO __construct() является общедоступной, вы не можете расширить ее с помощью закрытой функции __construct().

Так что «настоящий» синглтон невозможен.
Вы должны установить public function __construct().

0 голосов
/ 18 декабря 2017

Необходимость иметь разный уровень доступа между родительскими и дочерними конструкторами совершенно лецит , за исключением технических трудностей, связанных с исходным кодом PHP.

Фактически, это было зарегистрировано как ошибка ( # 61970 ).

В этом коммите, сделанном в марте 2017 года, если я не ошибаюсь, разработчик говорит, что он был закрыт:
http://git.php.net/?p=php-src.git;a=commitdiff;h=5324fb1f348f5bc979d9b5f13ac74177b73f9bf7

Я использую PHP 7.0.24, выпущенный в июле, но все еще вижу, что это не исправлено.

0 голосов
/ 07 марта 2016

Вам следует

1) отключить конструктор, установив для него значение private.

2) создать отдельный объект PDO, вызвав только статический метод.Статический метод должен возвращать экземпляр объекта PDO.

В Silex или Symfony вам придется ставить имя класса с префиксом "\" или использовать "use \ PDO;".Что больше ничего не значит, что это глобальный класс.

Ps.если вы установите __constructor в public и используете return functino, обратите внимание, что он не будет генерировать никаких исключений или предупреждений, но вы получите возвращенный объект класса, а не фактическое значение оператора return.

So $ db = new Database () вернул бы объект класса Database.Затем оттуда вам нужно будет получить доступ к вашему PDO, используя метод класса.$ pdo = $ db-> getInstance () Это неправильный способ создания правильного синглтона.

Если вам интересно больше узнать о плюсах и минусах одиночных игр и некоторых случаях их использования, прочитайте эту Наилучшая практика поPHP синглтон классы , вы найдете больше информации об этом шаблоне дизайна.

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

    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...