Использование одноэлементного класса базы данных в функциях и нескольких сценариях (PHP) — лучшие методы использования

У меня есть соединение singleton db, с которым я получаю:

$dbConnect = myDatabase::getInstance();

что достаточно легко. Мой вопрос: каков наименее риторический и законный способ использования этого соединения в функциях и классах? Кажется глупым объявлять переменную глобальной, передавать ее каждой отдельной функции и/или воссоздавать эту переменную внутри каждой функции. Есть ли другой ответ на это?

Очевидно, я нуб, и я могу обойти эту проблему 10 различными способами, ни один из которых не является для меня действительно привлекательным. Было бы намного проще, если бы эта переменная $dbConnect была доступна в любой функции без необходимости объявлять ее глобальной или передавать ее. Я знаю, что могу добавить переменную в массив $_SERVER... что-то не так с делая это? Мне это кажется несколько неуместным.

Еще один быстрый вопрос: это плохая практика:

$result = myDatabase::getInstance()->запрос($запрос);

непосредственно внутри функции?


person dscher    schedule 12.03.2010    source источник
comment
Вы ответили на свой вопрос, ваш пример использования именно так, как вы бы это сделали.   -  person Neel    schedule 12.03.2010
comment
Если вы планируете создать некоторые классы/функции, которые можно было бы использовать с несколькими базами данных одновременно (например, работая с 2+ базами данных одновременно), то лучше всегда передавать $dbConnect каждому классу/функции в качестве параметра, но если вы уверены, что всегда будете использовать только одну БД - тогда вы можете просто myDatabase::getInstance() в каждом классе/функции, когда вам это нужно   -  person Laimoncijus    schedule 07.04.2010
comment
Если вы измените getInstance(), чтобы он принимал параметр, указывающий, какое соединение вы хотите (с соответствующим значением по умолчанию), вы также можете обойти проблему с несколькими базами данных (при условии, что функция знает, с какой базой данных ей нужно общаться).   -  person El Yobo    schedule 09.04.2010


Ответы (4)


Что-то из этого придется по вкусу. На работе мы также получаем дескриптор соединения ADODB через

$db = Registry :: getDB();

Точно так же вы можете сократить часть этого кода, используя цепочку методов:

$name = Registry :: getDB()->getOne(
    "SELECT name FROM user WHERE user_id = ?", $userId
);

Использование реестра означает, что ваш вызывающий код имеет конкретную зависимость от вашего класса Registry. Это затрудняет тестирование вашего кода (лично это единственный раз, когда я бился головой о стену, используя реестр).

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

Вы все еще можете обойти это, изучив свою рабочую среду и настроив реестр с помощью класса абстракции фиктивной базы данных, но это не так элегантно, как внедрение зависимостей (DI).

Лучшее объяснение DI и контейнеров (для PHP-разработчика), которое я видел, это Внедрение зависимостей Фабьена Потенсье в PHP 5.3 (начиная со слайда 9).

Вы передаете контейнер DI вместо реестра, он обеспечивает элегантный и простой способ получить дескрипторы зависимостей (например, реестра), но является гибким и более слабо связанным, поэтому вы можете имитировать эти зависимости, когда это необходимо.

person Greg K    schedule 12.04.2010

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

Я бы сказал, что вы на правильном пути!

person ChrisR    schedule 07.04.2010
comment
Это был не его вопрос. Он не говорит, должен ли он использовать синглтоны (так и есть), он хочет знать, как передать ссылку на этот объект в своем коде. - person zaf; 07.04.2010
comment
@zaf, спасибо за разъяснение. @chris, это правильно ... я пытаюсь выяснить, какой самый ленивый, безопасный и наименее повторяющийся способ справиться с раздачей этого соединения с БД. Я знаю, что мог бы создать экземпляр в нижней части файла класса db и внедрить его в другие мои классы. Просто интересно, есть ли другой способ, который не так осуждается, как GLOBALS, чтобы сделать то же самое. Спасибо за отзыв. - person dscher; 07.04.2010
comment
Ну, если вы хотите держаться подальше от Globals (за что я не могу вас винить) и по-прежнему хотите, чтобы экземпляры классов были доступны во всем вашем приложении, вы можете взглянуть на шаблон реестра. - person ChrisR; 08.04.2010

Я использую суперглобальную переменную $GLOBALS для хранения соединения с базой данных. Творит чудеса.

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

Сейчас я надену беруши, готовый к стенаниям по поводу использования глобальных переменных!

@Downvoters - немного чтения перед сном:

Являются ли глобальные переменные плохими?

https://stackoverflow.com/questions/357187/global-variables-when-are-they-acceptable

Несколько цитат для вашего удовольствия:

«Глобальные переменные постоянно используются многими программистами. Сейчас мы называем их просто синглтонами.» — ДэнниСмурф

«Они полностью, принципиально, абсолютно, невероятно, поразительно злы.» — Винко Врсалович

И лучший ответ здесь от самого Клетуса: Являются ли глобальные переменные в PHP плохими упражняться? Если да, то почему?

person zaf    schedule 06.04.2010
comment
Я новичок в PHP, поэтому не могу комментировать, но с нетерпением жду, что другие могут подумать об этой идее. Спасибо, что подключились. - person dscher; 06.04.2010
comment
К сожалению, Globals считаются плохой вещью и плохой практикой, есть более безопасные, чистые и лучшие способы решить эту проблему, среди них Singleton. - person ChrisR; 07.04.2010
comment
если вы сохраните свой объект БД в $GLOBALS (скажем, вы сохраните его в $GLOBALS['DB']), есть риск, что вы всегда можете уничтожить его с помощью простого: $GLOBALS['DB'] = null; или unset($GLOBALS['DB']);, и тогда у вас не будет подключения к БД... Где использование myDatabase::getInstance() делает вас более безопасно, что он всегда там - person Laimoncijus; 07.04.2010
comment
@ChrisRamakers Смотрите мой комментарий к вашему ответу. Он что-то другое спрашивает. - person zaf; 07.04.2010
comment
@Laimoncijus Верно. Но я сказал быть благоразумным :) - person zaf; 07.04.2010
comment
@Loimoncijus, спасибо за ваш вклад. То, что вы сказали, имеет большой смысл. - person dscher; 07.04.2010
comment
Использование глобальных переменных просто приводит к беспорядочному коду. Это может быть неочевидно в небольших приложениях, таких как простой блог или форум, но это будет преследовать вас в больших проектах. Просто не используйте глобалы. В PHP5 буквально НЕТ ситуации, когда нужны глобальные переменные. - person selfawaresoup; 07.04.2010
comment
@Techpriester У ОП есть ситуация, и единственное решение - это то, которое я дал. Использование $GLOBALS не совсем похоже на использование глобальных переменных. Это не похоже на «глобальный $myvar». А ваше утверждение об НЕТ ситуации, когда нужны глобальные переменные - тогда что такое $_GET, $_POST, $_SERVER и т.д. и т.п.? - person zaf; 07.04.2010

Я имел дело с этим довольно много на протяжении многих лет. Я бы сказал, что добавление объекта, производного от Singleton, к суперглобальной переменной, такой как $_GLOBAL или $_SERVER, в первую очередь устраняет большую часть смысла создания класса Singleton.

Лучшей практикой, как я вижу, является доступ к нему, как вы предложили:

$result = Database_Class::singleton()->query('whatever');

Единственное, что я хотел бы добавить, это то, что в случае некоторой локальной области (например, функции или метода), где вы хотите использовать объект Singleton несколько раз, возможно, стоит сделать что-то вроде:

function func() {
  $db = Database_Class::singleton();
  $db->query('insert into whereever');
  $db->query('insert into whereever');
  $db->query('insert into whereever');
  $db->query('insert into whereever');
}
person Jonathan Hanson    schedule 11.04.2010
comment
Почему вы рекомендуете повторно создавать соединение, а не просто использовать уже доступное, такое как $this-›db-›query, если вы создали экземпляр объекта в конструкторе класса. Есть проблема со скоростью? - person dscher; 11.04.2010
comment
Классы Singleton не создают повторный экземпляр объекта при вызове метода singleton. Метод singleton всегда возвращает один и тот же объект (в отличие от нового объекта того же класса). en.wikipedia.org/wiki/Singleton_pattern Например: class MyClass { function singleton() { статический $cached_object = null; if( is_null($cached_object)) { $cached_object = new MyClass(); } вернуть $cached_object; } } Затем: $object = MyClass::singleton(); // Создает и возвращает новый объект $object = MyClass::singleton(); // Возвращает тот же кэшированный объект - person Jonathan Hanson; 13.04.2010
comment
Ungh, извините за отсутствие возврата каретки. Вы должны быть в состоянии собрать его вместе. - person Jonathan Hanson; 13.04.2010