В классе PHP5, когда вызывается частный конструктор? - PullRequest
37 голосов
/ 25 августа 2008

Допустим, я пишу класс PHP (> = 5.0), который должен быть одноэлементным. Все документы, которые я прочитал, говорят о том, что конструктор класса должен быть закрытым, так что класс не может быть напрямую создан.

Так что, если у меня есть что-то вроде этого:

class SillyDB
{
  private function __construct()
  {

  }

  public static function getConnection()
  {

  }
}

Есть ли случаи, когда __construct () вызывается иначе, чем если бы я делал

new SillyDB() 

позвонить в сам класс?

И почему мне вообще разрешено создавать SillyDB изнутри себя?

Ответы [ 5 ]

62 голосов
/ 25 августа 2008

__construct() будет вызываться только в том случае, если вы вызываете его из метода для класса, содержащего приватный конструктор. Так что для вашего синглтона у вас может быть такой метод:

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

6 голосов
/ 26 августа 2008

Вот очень простой синглтон, который просто генерирует строку даты / времени:

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()
    {

    }
}
4 голосов
/ 27 августа 2008

ОК, я провел несколько собственных тестов.

  • Если вы не объявите свой собственный конструктор в подклассе, попытка создать его экземпляр приведет к фатальной ошибке, потому что он попытается вызвать конструктор суперкласса.
  • В случае соединения с БД, когда вы, по-видимому, возвращаете (в любом случае в PHP) экземпляр mysqli или ресурс, возвращаемый функцией mysql_connect() (или какой-либо другой ссылкой на какую-либо другую СУБД), если Вы помечаете экземпляр как частный, нет угрозы, что кто-то создаст его подкласс и подделает ссылку.
  • Как я уже упоминал ранее, если кто-то действительно хочет переопределить ваше поведение и установить несколько соединений, он может также сделать это, написав новый класс.
2 голосов
/ 26 августа 2008

Проверьте код, Марк, и дайте мне знать, что вы найдете.

РЕДАКТИРОВАТЬ: Кроме того, в этой конкретной ситуации, я не уверен, почему вы должны быть заинтересованы в предотвращении подкласса человека. Если у кого-то есть доступ к вашему PHP-коду для его подкласса, то у него также есть доступ к вашему коду для его копирования и изменения модификаторов доступа на то, что они (по любой причине) сочтут подходящим.

Практическая полезность Singleton в этом случае заключается в том, что, используя его, вы можете гарантировать, что вы всегда используете одно и то же соединение с базой данных для данного HTTP-запроса. Это завершает это. Другие вещи (с использованием final и частных конструкторов) полезно знать с точки зрения теории, и еще более полезно знать, хотите ли вы распространять код качества API среди других программистов, но в случае этого конкретного примера все ключевые слова добавляют байты к размеру файла вашего класса.

0 голосов
/ 26 августа 2008

Немного придирки: для полноты вы, вероятно, объявили бы класс как окончательный , поскольку вы не хотели бы, чтобы кто-то создавал подклассы этого класса и реализовывал свой собственный открытый конструктор.

(Простите, если компилятор ловит переопределение приватного конструктора, но я не думаю, что это так)

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