Global или Singleton для подключения к базе данных? - PullRequest
78 голосов
/ 25 сентября 2008

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

Код с Глобальным

$conn = new PDO(...);

function getSomething()
{
    global $conn;
    .
    .
    .
}

код с синглтоном

class DB_Instance
{
    private static $db;

    public static function getDBO()
    {
        if (!self::$db)
            self::$db = new PDO(...);

        return self::$db;
    }
}

function getSomething()
{
    $conn = DB_Instance::getDBO();
    .
    .
    .
}

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

Ответы [ 9 ]

104 голосов
/ 20 октября 2008

Я знаю, что это старо, но ответ Dr8k был почти там.

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

Поставьте себе цель смягчить боль от внесения изменений в будущем: глобальный процесс опасен, потому что им трудно управлять в одном месте. Что если я хочу сделать этот контекст подключения к базе данных осведомленным в будущем? Что делать, если я хочу, чтобы он закрывался и снова открывался каждый раз, когда его использовали. Что если я решу, что в целях масштабирования моего приложения я хочу использовать пул из 10 соединений? Или настраиваемое количество соединений?

A Singleton Factory дает вам такую ​​гибкость. Я настроил это с очень маленькой дополнительной сложностью и получаю больше, чем просто доступ к тому же соединению; Я получаю возможность изменить способ передачи этой связи мне позже простым способом.

Обратите внимание, что я говорю синглтон-фабрика , а не просто синглтон . Правда, между синглтоном и глобальным различием очень мало. И из-за этого нет никакой причины иметь одноэлементное соединение: зачем вам тратить время на его настройку, когда вместо этого вы можете создать обычный глобал?

То, что получает от вас фабрика, - это то, почему нужно получить соединения, и отдельное место, чтобы решить, какие соединения (или соединение) вы собираетесь получить.

Пример * * тысяча двадцать-одна class ConnectionFactory { private static $factory; private $db; public static function getFactory() { if (!self::$factory) self::$factory = new ConnectionFactory(...); return self::$factory; } public function getConnection() { if (!$this->db) $this->db = new PDO(...); return $this->db; } } function getSomething() { $conn = ConnectionFactory::getFactory()->getConnection(); . . . } Затем, через 6 месяцев, когда ваше приложение станет супер известным и получит метку и косую черту, и вы решите, что вам нужно больше, чем одно соединение, все, что вам нужно сделать, это реализовать пул в методе getConnection (). Или, если вы решите, что вам нужна оболочка, которая реализует ведение журнала SQL, вы можете передать подкласс PDO. Или, если вы решите, что вы хотите новое соединение при каждом вызове, вы можете сделать это. Это гибкий, а не жесткий. 16 строк кода, включая фигурные скобки, которые сэкономят вам часы, часы и часы рефакторинга до чего-то жутко похожего в будущем. Обратите внимание, что я не рассматриваю это "Feature Creep", потому что я не делаю никакой реализации функций в первом раунде. Это граница "Future Creep", но в какой-то момент идея, что "кодирование для завтрашнего дня сегодня" это всегда , плохая вещь для меня не вяжется.

16 голосов
/ 25 сентября 2008

Я не уверен, что могу ответить на ваш конкретный вопрос, но хотел предположить, что глобальные / одноэлементные объекты соединения могут быть не лучшей идеей, если это для веб-системы. СУБД, как правило, предназначены для эффективного управления большим количеством уникальных соединений. Если вы используете глобальный объект соединения, то вы делаете несколько вещей:

  1. Заставляя вас страницы делать всю базу данных соединения последовательно и убийство любые попытки асинхронной страницы грузы.

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

  3. Максимальное общее количество одновременные подключения ваши База данных может поддерживать и блокировать новые пользователи от доступа к ресурсы.

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

[EDIT]

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

При использовании пула соединений поддерживается ряд отдельных соединений. Когда приложению требуется соединение, первое доступное соединение из пула извлекается, а затем возвращается в пул после выполнения его работы. Если запрашивается соединение, и ни одно из них не доступно, произойдет одно из двух: a) если не достигнуто максимальное количество разрешенных соединений, новое соединение открывается, или b) приложение вынуждено ждать, пока соединение станет доступным .

Примечание: В языках .Net пул соединений по умолчанию обрабатывается объектами ADO.Net (строка соединения задает всю необходимую информацию).

Спасибо Крэду за комментарии.

7 голосов
/ 13 декабря 2011

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

Поэтому я бы проигнорировал global и Singleton, так как они на самом деле не ООП.

То, что вы искали, это внедрение зависимостей .

Вы можете проверить простую для чтения информацию на основе PHP, связанную с внедрением зависимостей (с примерами), по адресу http://components.symfony -project.org / dependency-инъекция / trunk / book / 01-Dependency-Injection

3 голосов
/ 25 сентября 2008

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

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

Еще одно незначительное отличие заключается в том, что глобальная реализация может непреднамеренно попирать другие имена переменных в приложении. Маловероятно, что вы когда-нибудь случайно объявите другую глобальную ссылку на $ db, хотя возможно, что вы могли бы случайно перезаписать ее (скажем, вы пишете if ($ db = null), когда вы хотели написать if ($ db == null). Единственный объект предотвращает это.

2 голосов
/ 25 сентября 2008

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

2 голосов
/ 25 сентября 2008

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

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

1 голос
/ 25 сентября 2008

В общем, я бы использовал одноэлементное соединение для соединения с базой данных ... Вы не хотите создавать новое соединение каждый раз, когда вам нужно взаимодействовать с базой данных ... Это может повредить производительности и пропускной способности вашей сети ... Зачем создавать новый, когда есть один доступный ... Только мои 2 цента ...

RWendi

0 голосов
/ 27 мая 2018

В качестве совета оба singleton и global действительны и могут быть объединены в одной системе, проекте, плагине, продукте и т. Д. ... В моем случае я делаю цифровые продукты для веб (плагин).

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

<?php // file0.php

final class Main_Class
{
    private static $instance;
    private $time;

    private final function __construct()
    {
        $this->time = 0;
    }
    public final static function getInstance() : self
    {
        if (self::$instance instanceof self) {
            return self::$instance;
        }

        return self::$instance = new self();
    }
    public final function __clone()
    {
        throw new LogicException("Cloning timer is prohibited");
    }
    public final function __sleep()
    {
        throw new LogicException("Serializing timer is prohibited");
    }
    public final function __wakeup()
    {
        throw new LogicException("UnSerializing timer is prohibited");
    }
}

Global используется практически для всех средних классов, например:

<?php // file1.php
global $YUZO;
$YUZO = new YUZO; // YUZO is name class

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

<?php // file2.php
global $YUZO;
$YUZO->method1()->run();
$YUZO->method2( 'parameter' )->html()->print();

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

In conclusion:, вы должны, если вы уже хорошо понимаете, что такое анти-паттерн Singleton и понимать Global , вы можете использовать один из 2 вариантов или смешать их, но если я рекомендую не злоупотреблять, так как есть много программистов, которые очень исключительны и верны программированию ООП, используйте его для основных и дополнительных классов, которые вы часто используете во время выполнения. (Это экономит вам много ресурсов процессора). ?

0 голосов
/ 25 сентября 2008

Это довольно просто. Никогда не используйте глобальный ИЛИ синглтон.

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