web-dev-qa-db-fra.com

Global ou Singleton pour la connexion à la base de données?

Quel est l'avantage d'utiliser singleton au lieu de global pour les connexions de base de données en PHP? Je pense que l'utilisation de singleton au lieu de global rend le code inutilement complexe.

Code avec Global

$conn = new PDO(...);

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

Code avec Singleton

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();
    .
    .
    .
}

S'il existe un meilleur moyen d'initialiser une connexion à une base de données autre que global ou singleton, veuillez le mentionner et décrire les avantages qu'il présente par rapport à global ou singleton.

78
Imran

Je sais que c'est vieux, mais la réponse de Dr8k était presque là-bas.

Lorsque vous envisagez d'écrire un morceau de code, supposez que cela va changer. Cela ne signifie pas que vous supposez le type de changements qu'il aura sur lui à un moment donné dans le futur, mais plutôt qu'une certaine forme de changement sera apportée.

En faire un objectif atténue la douleur de faire des changements à l'avenir: un global est dangereux car il est difficile à gérer en un seul endroit. Que faire si je souhaite rendre ce contexte de connexion à la base de données plus tard? Et si je veux qu'il se ferme et se rouvre lui-même toutes les 5 fois qu'il a été utilisé. Et si je décide que dans le but de faire évoluer mon application, je souhaite utiliser un pool de 10 connexions? Ou un nombre configurable de connexions?

Un singleton factory vous donne cette flexibilité. Je l'ai installé avec très peu de complexité supplémentaire et gagne plus qu'un simple accès à la même connexion; Je gagne la possibilité de changer la façon dont cette connexion me sera transmise plus tard de manière simple.

Notez que je dis singleton factory par opposition à simplement singleton . Il y a une petite différence précieuse entre un singleton et un global, c'est vrai. Et à cause de cela, il n'y a aucune raison d'avoir une connexion singleton: pourquoi passeriez-vous le temps à le configurer alors que vous pourriez créer un global régulier à la place?

Qu'est-ce qu'une usine vous obtient est une raison pour laquelle obtenir des connexions, et un endroit séparé pour décider quelles connexions (ou connexion) vous allez obtenir.

Exemple

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();
    .
    .
    .
}

Ensuite, dans 6 mois, lorsque votre application est super célèbre et devient dugg et slashdotted et que vous décidez que vous avez besoin de plus d'une seule connexion, tout ce que vous avez à faire est d'implémenter un certain regroupement dans la méthode getConnection (). Ou si vous décidez que vous voulez un wrapper qui implémente la journalisation SQL, vous pouvez passer une sous-classe PDO. Ou si vous décidez que vous souhaitez une nouvelle connexion à chaque appel, vous pouvez le faire. C'est flexible, au lieu de rigide.

16 lignes de code, y compris les accolades, qui vous feront économiser des heures et des heures et des heures de refactoring à quelque chose de étrangement similaire sur toute la ligne.

Notez que je ne considère pas ce "Feature Creep" parce que je ne fais aucune implémentation de fonctionnalité dans le premier tour. C'est la frontière "Future Creep", mais à un moment donné, l'idée que "coder pour demain aujourd'hui" est toujours une mauvaise chose ne pleure pas moi.

104
Jon Raphaelson

Je ne suis pas sûr de pouvoir répondre à votre question spécifique, mais je voulais suggérer que les objets de connexion global/singleton ne sont peut-être pas la meilleure idée si cela concerne un système basé sur le Web. Les SGBD sont généralement conçus pour gérer un grand nombre de connexions uniques de manière efficace. Si vous utilisez un objet de connexion globale, vous effectuez deux ou trois choses:

  1. Forcer vos pages à effectuer toutes les connexions à la base de données de manière séquentielle et tuer toutes les tentatives de chargement de pages asynchrones.

  2. Maintenir potentiellement des verrous ouverts sur les éléments de la base de données plus longtemps que nécessaire, ce qui ralentit les performances globales de la base de données.

  3. Maximiser le nombre total de connexions simultanées que votre base de données peut prendre en charge et empêcher les nouveaux utilisateurs d'accéder aux ressources.

Je suis sûr qu'il y a aussi d'autres conséquences potentielles. N'oubliez pas que cette méthode tentera de maintenir une connexion à la base de données pour chaque utilisateur accédant au site. Si vous n'avez qu'un ou deux utilisateurs, pas de problème. S'il s'agit d'un site Web public et que vous souhaitez du trafic, l'évolutivité deviendra un problème.

[MODIFIER]

Dans des situations à plus grande échelle, la création de nouvelles connexions à chaque fois que vous atteignez la base de données peut être mauvaise. Cependant, la réponse n'est pas de créer une connexion globale et de la réutiliser pour tout. La réponse est la mise en commun des connexions.

Avec le regroupement de connexions, un certain nombre de connexions distinctes sont conservées. Lorsqu'une connexion est requise par l'application, la première connexion disponible du pool est récupérée, puis renvoyée au pool une fois son travail terminé. Si une connexion est demandée et qu'aucune n'est disponible, deux choses se produisent: a) si le nombre maximal de connexions autorisées n'est pas atteint, une nouvelle connexion est ouverte, ou b) l'application est obligée d'attendre qu'une connexion soit disponible .

Remarque: Dans les langages .Net, le regroupement de connexions est géré par défaut par les objets ADO.Net (la chaîne de connexion définit toutes les informations requises).

Merci à Crad d'avoir commenté cela.

16
Dr8k

La méthode singleton a été créée pour s'assurer qu'il n'y avait qu'une seule instance d'une classe. Mais, parce que les gens l'utilisent comme un moyen de raccourcir la mondialisation, il devient connu comme une programmation paresseuse et/ou mauvaise.

Par conséquent, j'ignorerais global et Singleton car les deux ne sont pas vraiment des POO.

Ce que vous cherchiez, c'est injection de dépendance .

Vous pouvez vérifier des informations faciles à lire PHP basées sur l'injection de dépendance (avec des exemples) sur http://components.symfony-project.org/dependency-injection/trunk/ book/01-Dependency-Injection

7
user1093284

Les deux modèles produisent le même effet net, fournissant un seul point d'accès pour vos appels de base de données.

En termes d'implémentation spécifique, le singleton a un petit avantage de ne pas initier de connexion à la base de données jusqu'à ce qu'au moins une de vos autres méthodes le demande. En pratique, dans la plupart des applications que j'ai écrites, cela ne fait pas beaucoup de différence, mais c'est un avantage potentiel si vous avez des pages/chemins d'exécution qui ne font aucun appel à la base de données, car ces pages ne le feront pas. jamais demander une connexion à la base de données.

Une autre différence mineure est que l'implémentation globale peut piétiner involontairement d'autres noms de variables dans l'application. Il est peu probable que vous déclariez accidentellement une autre référence globale $ db, mais il est possible que vous puissiez l'écraser accidentellement (par exemple, vous écrivez if ($ db = null) lorsque vous vouliez écrire if ($ db == null). L'objet singleton empêche cela.

3
Adam Ness

Si vous n'utilisez pas une connexion persistante, et il y a des cas pour ne pas le faire, je trouve qu'un singleton est conceptuellement plus acceptable qu'un global dans la conception OO.

Dans une véritable architecture OO, un singleton est plus efficace que de créer une nouvelle instance de l'objet à chaque fois.

2
Gavin M. Roy

Sur l'exemple donné, je ne vois aucune raison d'utiliser des singletons. En règle générale, si mon seul souci est de permettre une seule instance d'un objet, si le langage le permet, je préfère utiliser des globales

2
Dprado

En général, j'utiliserais un singleton pour une connexion à la base de données ... Vous ne voulez pas créer une nouvelle connexion à chaque fois que vous devez interagir avec la base de données ... Cela pourrait nuire aux performances et à la bande passante de votre réseau ... Pourquoi créer un nouveau, quand il y en a un disponible ... Juste mes 2 cents ...

RWendi

1
RWendi

C'est assez simple. N'utilisez jamais global OR Singleton.

0
1800 INFORMATION

Comme conseil, les deux singleton et global sont valides et peuvent être joints au sein du même système, projet, plugin, produit, etc. ... Dans mon cas, je fais des produits numériques pour le web (plugin).

J'utilise uniquement singleton dans la classe principale et je l'utilise par principe. Je ne l'utilise presque pas car je sais que la classe principale ne l'instanciera plus

<?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 utiliser pour presque toutes les classes secondaires, exemple:

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

pendant l'exécution, je peux utiliser Global pour appeler leurs méthodes et attributs dans la même instance car je n'ai pas besoin d'une autre instance de ma classe de produit principale.

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

J'obtiens avec le global est d'utiliser la même instance pour pouvoir faire fonctionner le produit car je n'ai pas besoin d'une fabrique pour les instances de la même classe, généralement la fabrique d'instance est pour les gros systèmes ou à des fins très rares.

In conclusion:, vous devez si vous comprenez déjà bien l'anti-pattern Singleton et comprenez le Global, vous pouvez utiliser l'une des 2 options ou les mélanger mais si je recommande de ne pas abuser car il existe de nombreux programmeurs qui sont très exceptionnels et fidèles au POO de programmation, utilisez-le pour les classes principales et secondaires que vous utilisez beaucoup pendant le temps d'exécution. (Cela vous fait économiser beaucoup de CPU). ????

0
Lenin Zapata