Существует ли прецедент для одиночных игр с доступом к базе данных в PHP?

Я получаю доступ к моей базе данных MySQL через PDO. Я настраиваю доступ к базе данных, и моя первая попытка состояла в следующем:

Первое, что я подумал, это global:

$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');

function some_function() {
    global $db;
    $db->query('...');
}

Это считается плохой практикой. После небольшого поиска я оказался с шаблоном Singleton, который

"применяется к ситуациям, в которых должен быть один экземпляр класса."

В соответствии с примером в руководстве мы должны сделать следующее:

class Database {
    private static $instance, $db;

    private function __construct(){}

    static function singleton() {
        if(!isset(self::$instance))
            self::$instance = new __CLASS__;

        return self:$instance;
    }

    function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')

        return self::$db;
    }
}

function some_function() {
    $db = Database::singleton();
    $db->get()->query('...');
}

some_function();

Зачем мне этот относительно большой класс, когда я могу это сделать?

class Database {
    private static $db;

    private function __construct(){}

    static function get() {
        if(!isset(self::$rand))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');

        return self::$db;
    }
}

function some_function() {
    Database::get()->query('...');
}

some_function();

Этот последний работает отлично, и мне больше не нужно беспокоиться о $db.

Как я могу создать меньший одноэлементный класс, или есть прецедент для одиночных игр, которые мне не хватает в PHP?

Ответ 1

Хорошо, я задавался этим вопросом некоторое время, когда я впервые начал свою карьеру. Реализовала его разными способами и придумала две причины, чтобы не использовать статические классы, но они довольно большие.

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

Если это произойдет, если вы использовали статический класс, у вас есть гораздо худший рефакторинг, чем если бы вы использовали синглтон. Синглтон является шаблоном iffy сам по себе, но он легко конвертируется в интеллектуальный шаблон factory - может даже быть преобразован для использования инъекции зависимостей без особых проблем. Например, если ваш синглтон получен через getInstance(), вы можете легко изменить это на getInstance (имя базы данных) и разрешить несколько баз данных - никаких других изменений кода.

Вторая проблема - тестирование (и, честно говоря, это то же самое, что и первая проблема). Иногда вы хотите заменить свою базу данных макетной базой данных. Фактически это второй экземпляр объекта базы данных. Это гораздо сложнее сделать со статическими классами, чем с одним синглэном, вам нужно только обмануть метод getInstance(), а не каждый метод в статическом классе (который на некоторых языках может быть очень сложным).

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

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

Ответ 2

Синглтоны имеют очень мало - если не сказать "нет" - используют в PHP.

В языках, где объекты живут в общей памяти, Singletons можно использовать, чтобы поддерживать низкий уровень использования памяти. Вместо создания двух объектов вы ссылаетесь на существующий экземпляр из глобальной памяти приложений. В PHP нет такой памяти приложения. Синглтон, созданный в одном запросе, живет именно для этого запроса. Синглтон, созданный в другом Запросе, выполненном одновременно, по-прежнему является совершенно другим экземпляром. Таким образом, одна из двух основных целей Singleton здесь не применима.

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

Другой целью было бы иметь глобальную точку доступа к экземпляру в рамках одного и того же запроса. Хотя это может показаться желательным, на самом деле это не так, потому что оно создает связь с глобальным охватом (например, любые глобальные и статические). Это упрощает тестирование устройств, а ваше приложение в целом менее обслуживается. Есть способы смягчить это, но в целом, если вам нужно иметь один и тот же экземпляр во многих классах, используйте Injection Dependency.

Смотрите мои слайды для Синглоты в PHP - Почему они плохие и как их можно устранить из ваших приложений для получения дополнительной информации.

Даже Эрих Гамма, один из изобретателей шаблонов Singleton, сейчас сомневается в этом шаблоне:

Я за отказ от Singleton. Его использование почти всегда является запахом дизайна

Дальнейшее чтение

Если после вышесказанного вам по-прежнему нужна помощь:

Singleton Decision Diagram

Ответ 3

Кому нужны синглтоны в PHP?

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

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

См., шаблон singleton является включенным. Когда это сделано, класс singleton является жестким по любому коду, в который вы его включаете, и он действует точно так же, как вы создали его методы и переменные. И это всегда один и тот же объект в заданном запросе. Поскольку он не может быть создан дважды, чтобы быть двумя разными объектами, вы знаете, что одноэлементный объект находится в любой заданной точке кода, даже если одноэлемент вставляется в два, три разных, старых и даже спайкетинговых кода. Таким образом, упрощается с точки зрения целей разработки - даже если в этом проекте много людей, когда вы видите, что одноэлемент инициализируется в одной точке в любой заданной кодовой базе, вы знаете, что это такое, что он делает, как это делается и состояние, в котором оно находится. Если это был традиционный класс, вам нужно было бы отслеживать, где был создан этот объект, какие методы были задействованы в нем до этой точки в коде и его конкретное состояние. Но, оставьте там один синглтон, и если вы отбросили правильные методы отладки и информации и отслеживания в синглтон при его кодировании, вы точно знаете, что это такое. Таким образом, это облегчает людям, которые должны работать с разными кодовыми базами, с необходимостью интеграции кода, который был сделан ранее с разными философиями или сделан людьми, с которыми у вас нет контакта. (т.е. компания-производитель-компания-то, чего там больше нет, ничего не поддерживают).

- Люди, которым необходимо работать с сторонними API-интерфейсами, службами и веб-сайтами.

Если вы посмотрите ближе, это не слишком отличается от предыдущего случая - сторонние API, сервисы, веб-сайты - это как внешние, изолированные кодовые базы, над которыми у вас нет контроля. Все может случиться. Таким образом, с singleton session/user class вы можете управлять любым видом сеанса/авторизации от сторонних поставщиков, таких как OpenID, Facebook, Twitter и многое другое - и вы может делать эти ВСЕ в одно и то же время от САМОГО одноэлементного объекта - который легко доступен в известном состоянии в любой точке в любом коде, в который вы его подключаете. Вы даже можете создавать несколько сеансов для нескольких разных сторонних API/сервисов для пользователя SAME на своем собственном веб-сайте/приложении и делать все, что вы хотите с ними делать.

Конечно, все это также может быть тоном с традиционными методами, используя обычные классы и объекты. Ловушка здесь, singleton является более аккуратным, опрятным и, следовательно, из-за этого легко управляемым/тестируемым по сравнению с традиционным использованием класса/объекта в такие ситуации.

- Люди, которым необходимо быстро развиваться

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

Вы получаете идею. Теперь давайте перейдем к возражениям против одиночек и нечестивый крестовый поход против чего-то полезного:

- Прежде всего возражение состоит в том, что он делает тестирование сложнее.

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

В одном случае это возражение падает в этом отношении, оно игнорирует тот факт, что разработанные приложения причин не для "тестирования", а тестирование - это не единственная фаза/процесс, который входит в разработку приложения. Приложения разработаны для использования в производстве. И как я объяснил в разделе "Кто нуждается в синглтонах", синглтоны могут разрешить БОЛЬШУЮ сделку от сложности того, чтобы заставить кодовую работу WITH и INSIDE много разных кодовых баз/приложений/сторонних сервисов. Время, которое может быть потеряно при тестировании, - это время, затраченное на разработку и развертывание. Это особенно полезно в эту эпоху сторонней аутентификации/приложения/интеграции - Facebook, Twitter, OpenID, многие другие, и кто знает, что дальше.

Хотя это понятно - программисты работают в самых разных обстоятельствах в зависимости от их карьеры. И для людей, которые работают в относительно крупных компаниях с определенными отделами, которые предпочитают различные, определенные программные продукты/приложения в удобной манере и без надвигающейся гибели бюджетных сокращений/увольнений и сопутствующей необходимости делать много вещей с множеством разных вещей в дешевая/быстрая/надежная мода, синглтоны могут показаться не столь необходимыми. И это может быть даже неприятностью/помехой тому, что УЖЕ есть.

Но для тех, кто нуждается в работе в грязных траншеях "гибкого" развития, вынуждая выполнять множество разных запросов (иногда необоснованных) от своего клиента/менеджера/проекта, синглтоны являются экономией из-за причин, объясненных ранее.

. Еще одно возражение состоит в том, что его объем памяти выше

Поскольку новый синглтон будет существовать для каждого запроса от каждого клиента, это МОЖЕТ быть возражением для PHP. С плохо сконструированными и используемыми синглонами объем памяти приложения может быть выше, если многие пользователи обслуживаются приложением в любой заданной точке.

Хотя, это справедливо для ЛЮБОГО подхода, который вы можете использовать при кодировании. Вопросы, которые следует задать, - это методы, данные, которые удерживаются и обрабатываются этими синглетонами, ненужными? Ибо, если они нужны во многих запросах приложения, то даже если вы не используете синглтоны, эти методы и данные будут присутствовать в вашем приложении в той или иной форме через код. Таким образом, все становится вопросом, сколько памяти вы будете экономить, когда вы инициализируете традиционный объект класса 1/3 в обработке кода и уничтожаете его 3/4.

Смотрите, когда это делается, вопрос становится совершенно неуместным - не должно быть ненужных методов, данных, хранящихся в объектах вашего кода. ANYway - независимо от того, используете ли вы одиночные или нет. Таким образом, это возражение против синглтонов становится действительно смешным в этом, оно ПРИНИМАЕТ, что будут ненужные методы, данные в объектах, созданных из используемых вами классов.

- Некоторые недопустимые возражения типа "делает невозможным/сложнее поддерживать несколько соединений с базой данных"

Я даже не могу понять это возражение, когда все нужно поддерживать несколько соединений с базой данных, множественный выбор базы данных, несколько запросов к базе данных, множество наборов результатов в заданном одноэлементном режиме просто удерживают их в переменных/массивах в одноэлементном до тех пор, пока они необходимы. Это может быть так же просто, как хранить их в массивах, хотя вы можете придумать любой метод, который вы хотите использовать для его создания. Но рассмотрим простейший случай, использование переменных и массивов в заданном одноэлементном:

Представьте, что приведенное ниже значение находится внутри заданной базы данных singleton:

$this → connections = массив(); (неправильный синтаксис, я просто набрал его так, чтобы дать вам изображение - правильное объявление переменной является общедоступным $connections = array(), и его использование - это $this- > connections ['connectionkey] естественно)

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

$это → запрос (QueryString, 'queryname', $этом- > соединения [ 'particulrconnection']);

Что может просто выполнить запрос к выбранной базе данных с выбранным соединением и просто сохранить в своем

$это → Результаты

с ключом "queryname". Конечно, для этого вам понадобится код запроса, который тривиально делать.

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

КУРС, вы, естественно, должны освобождать результирующие наборы и соединения, когда это не нужно, но это само собой разумеется, и это не является специфическим для одиночных или любого другого метода/стиля/концепции кодирования.

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

Короче говоря, singleton patterns - это еще один метод/стиль/философия для программирования, и они так же полезны, как и другие, когда они используются в правильном месте, в правильном порядке. Что не отличается от всего.

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

Посмотрите на него - все, что неправильно используется, злоупотребляет, злоупотребляет, злонамеренно. Это не ограничивается каким-либо языком, любой концепцией кодирования, любым методом. Всякий раз, когда вы видите, что кто-то выпускает общие заявления, такие как "X is evil", убегайте от этой статьи. Шансы очень высоки, что это продукт ограниченной точки зрения - даже если точка зрения является результатом многолетнего опыта в чем-то конкретном, что обычно заканчивается тем, что он слишком много работает в данном стиле/методе - типичном интеллектуальном консерватизме.

Для этого могут быть даны бесконечные примеры: от "глобалы злые" до "iframes are evil". Еще около 10 лет назад даже предложение использовать iframe в любом данном приложении было ересью. Затем приходит Facebook, iframes везде, и посмотрите, что произошло - iframes не так злы.

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

Первым преимуществом программиста/программиста/программиста является свободный, открытый и гибкий ум.

Ответ 4

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

Чтобы ответить на вопрос, вы правы, что одиночные игры здесь переполнены. Простая переменная или функция. Однако лучшим (более надежным) подходом было бы использовать инъекцию зависимостей, чтобы полностью исключить глобальные переменные.

Ответ 5

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

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

НО: Мы не имеем представления о размере и сфере действия вашего проекта. Если это простой код, возможно, выбросить, что вряд ли нужно будет изменить, тогда да, идите и используйте статические члены. Но, если вы считаете, что вашему проекту может потребоваться масштабирование или подготовка к кодированию обслуживания вниз по дороге, то да, вы можете использовать шаблон Singleton.

Ответ 6

Во-первых, я просто хочу сказать, что я не очень часто использую шаблон Singleton. Зачем нужно, чтобы один объект полностью обрабатывал все приложение? Специально для баз данных, что делать, если я хочу подключиться к другому серверу базы данных? Я должен каждый раз отключать и снова подключаться...? В любом случае...

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

  • Сложно unit test
  • Проблемы с впрыском зависимостей
  • Может создавать проблемы с блокировкой (многопоточное приложение)

Использование статических классов вместо экземпляра singleton также приводит к некоторым из тех же недостатков, потому что самая большая проблема с singleton - это статический метод getInstance.

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

class Single {

    static private $_instance = false;

    public function __construct() {
        if (self::$_instance)
           throw new RuntimeException('An instance of '.__CLASS__.' already exists');

        self::$_instance = true;
    }

    private function __clone() {
        throw new RuntimeException('Cannot clone a singleton class');
    }

    public function __destruct() {
        self::$_instance = false;
    }

}

$a = new Single;
$b = new Single; // error
$b = clone($a); // error
unset($a);
$b = new Single; // works

Это поможет в первую очередь указать пункты: unit testing и dependency injection; при этом убедитесь, что в вашем приложении существует один экземпляр класса. Вы могли бы, например, просто передать результирующий объект вашим моделям (шаблон MVC) для их использования.

Ответ 7

Рассмотрим, как ваше решение отличается от того, которое представлено в документах PHP. Фактически, существует только одна "маленькая" разница: ваше решение предоставляет вызывающим абонентам getter с экземпляром PDO, в то время как тот, который в документах предоставляет вызывающим абонентам Database::singleton с экземпляром Database (они затем используют getter на этом, чтобы получить экземпляр PDO).

Итак, какой вывод мы достигаем?

  • В коде документации получатели получают экземпляр Database. Класс Database может выставлять (на самом деле, он должен разоблачить, если вы перейдете ко всем этим проблемам) более богатый или более высокий уровень интерфейса, чем объект PDO, который он обертывает.
  • Если вы измените свою реализацию, чтобы вернуть другой (более богатый) тип, чем PDO, то две реализации эквивалентны. Нет никакой выгоды от выполнения ручного внедрения.

С практической стороны, Singleton - довольно спорный образец. Это происходит главным образом потому, что:

  • Это злоупотребление. Новичкам программистам громать Синглтон намного легче, чем они замаскивают другие шаблоны. Затем они продолжают применять свои новообретенные знания везде, даже если проблема под рукой может быть решена лучше без Singleton (когда вы держите молоток, все выглядит как гвоздь).
  • В зависимости от языка программирования реализация Singleton в герметичном, негерметичном режиме может оказаться титанической задачей (особенно если у нас есть расширенные сценарии: синглтон в зависимости от другого синглтона, синглтонов, которые могут быть уничтожены, и т.д.). Просто попробуйте найти "окончательную" реализацию Синглтона на С++, я смею вас (у меня есть Андрей Александреску, новаторский Modern С++ Design, который документирует большую часть беспорядка).
  • Он накладывает дополнительную рабочую нагрузку как при кодировании Singleton, так и при написании кода для доступа к ней, рабочей нагрузки, которой вы можете обойтись, не следуя нескольким самоналоженным ограничениям на то, что вы пытаетесь сделать с вашими программными переменными.

Итак, в качестве окончательного вывода: ваш синглтон в порядке. Не использовать Singleton вообще просто отлично в течение большей части времени.

Ответ 8

Я не вижу в этом никакого смысла. Если вы внедрили класс таким образом, чтобы строка подключения была взята в качестве параметра конструктору и поддерживала список объектов PDO (один для каждая уникальная строка соединения), тогда, возможно, будет какая-то польза, но реализация singleton в этом случае кажется бессмысленным упражнением.

Ответ 9

Ваша интерпретация верна. Синглтоны имеют свое место, но злоупотребляют. Часто доступ к статическим функциям-членам достаточно (особенно, когда вам не нужно каким-либо образом контролировать время создания). Лучше, вы можете просто поместить некоторые свободные функции и переменные в пространство имен.

Ответ 10

При программировании нет "правильных" и "неправильных"; есть "хорошая практика" и "плохая практика".

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

Если у вас есть простой маленький класс, который не следует создавать несколько раз, вам не нужно делать его синглом. Это просто защитная сетка, если вы это сделаете.

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

Ответ 11

Вы ничего не пропустили, насколько я вижу. Пример довольно ошибочен. Это будет иметь значение, если в классе singleton были некоторые нестатические переменные экземпляра.