wake-up-neo.net

Global o Singleton per la connessione al database?

Quali sono i vantaggi dell'utilizzo di singleton anziché globale per le connessioni al database in PHP? Sento che usare singleton anziché global rende il codice inutilmente complesso.

Codice con Global

$conn = new PDO(...);

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

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

Se esiste un modo migliore di inizializzare la connessione al database diverso da global o singleton, si prega di menzionarlo e descrivere i vantaggi che ha su global o singleton.

78
Imran

So che questo è vecchio, ma la risposta di Dr8k è stata quasi lì.

Quando stai pensando di scrivere un pezzo di codice, supponi che cambierà. Ciò non significa che stai assumendo i tipi di modifiche che verranno sollevate su di esso ad un certo punto in futuro, ma piuttosto che verrà apportata una qualche forma di modifica.

Trasformarlo in un obiettivo attenua la sofferenza di apportare cambiamenti in futuro: un globale è pericoloso perché è difficile da gestire in un unico punto. Cosa succede se voglio rendere consapevole quel contesto di connessione al database in futuro? E se volessi che si chiudesse e si riaprisse ogni 5 volte che veniva usato. Cosa succede se decido che, nell'interesse del ridimensionamento della mia app, voglio usare un pool di 10 connessioni? O un numero configurabile di connessioni?

A singleton factory ti dà quella flessibilità. L'ho impostato con pochissima complessità extra e guadagno più di un semplice accesso alla stessa connessione; Ottengo la possibilità di cambiare il modo in cui questa connessione mi viene passata in seguito in modo semplice.

Nota che dico singleton factory anziché semplicemente singleton . C'è una piccola differenza preziosa tra un singleton e un globale, vero. E per questo motivo, non c'è motivo di avere una connessione singleton: perché dovresti passare il tempo a configurarlo quando invece potresti creare un normale globale?

Ciò che ti dà una fabbrica è un motivo per ottenere connessioni e un posto separato per decidere quali connessioni (o connessioni) otterrai.

Esempio

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

Quindi, in 6 mesi quando la tua app è super famosa e diventa dugg e slashdotted e decidi che hai bisogno di più di una singola connessione, tutto ciò che devi fare è implementare un pool nel metodo getConnection (). Oppure, se si decide che si desidera un wrapper che implementa la registrazione SQL, è possibile passare una sottoclasse PDO. Oppure, se decidi di desiderare una nuova connessione per ogni invocazione, puoi farlo. È flessibile, anziché rigido.

16 righe di codice, incluse le parentesi graffe, che ti faranno risparmiare ore, ore e ore di refactoring a qualcosa di stranamente simile lungo la linea.

Nota che non considero questo "Feature Creep" perché non sto eseguendo alcuna implementazione di funzionalità nel primo round. È una linea di confine "Future Creep", ma a un certo punto, l'idea che "codificare per domani oggi" sia sempre una cosa negativa non è all'altezza me.

104
Jon Raphaelson

Non sono sicuro di poter rispondere alla tua domanda specifica, ma volevo suggerire che gli oggetti connessione globale/singleton potrebbero non essere la migliore idea se questo fosse per un sistema basato sul web. I DBMS sono generalmente progettati per gestire un numero elevato di connessioni univoche in modo efficiente. Se stai utilizzando un oggetto connessione globale, stai facendo un paio di cose:

  1. Costringendo le tue pagine a eseguire tutte le connessioni al database in sequenza e uccidendo qualsiasi tentativo di caricamento di pagine asincrone.

  2. Mantenere potenzialmente blocchi aperti sugli elementi del database più a lungo del necessario, rallentando le prestazioni complessive del database.

  3. Massimizzare il numero totale di connessioni simultanee che il database può supportare e impedire ai nuovi utenti di accedere alle risorse.

Sono sicuro che ci sono anche altre potenziali conseguenze. Ricorda, questo metodo tenterà di sostenere una connessione al database per ogni utente che accede al sito. Se hai solo uno o due utenti, non è un problema. Se si tratta di un sito Web pubblico e si desidera il traffico, la scalabilità diventerà un problema.

[EDIT]

In situazioni di dimensioni più grandi, la creazione di nuove connessioni ogni volta che si colpisce il database può essere dannosa. Tuttavia, la risposta non è quella di creare una connessione globale e riutilizzarla per tutto. La risposta è il pool di connessioni.

Con il pool di connessioni, vengono mantenute diverse connessioni distinte. Quando l'applicazione richiede una connessione, la prima connessione disponibile dal pool viene recuperata e quindi restituita al pool al termine del lavoro. Se viene richiesta una connessione e nessuna è disponibile, si verificherà una delle due cose seguenti: a) se non viene raggiunto il numero massimo di connessione consentita, viene aperta una nuova connessione oppure b) l'applicazione è costretta ad attendere che una connessione diventi disponibile .

Nota: Nei linguaggi .Net, il pool di connessioni è gestito per impostazione predefinita dagli oggetti ADO.Net (la stringa di connessione imposta tutte le informazioni richieste).

Grazie a Crad per aver commentato questo.

16
Dr8k

Il metodo singleton è stato creato per assicurarsi che esistesse solo un'istanza di qualsiasi classe. Ma poiché la gente lo usa come un modo per scorciatoia verso la globalizzazione, diventa noto come programmazione pigra e/o cattiva.

Pertanto, ignorerei global e Singleton poiché entrambi non sono realmente OOP.

Quello che stavi cercando è iniezione di dipendenza .

Puoi controllare le informazioni facili da leggere PHP relative all'iniezione delle dipendenze (con esempi) su http://components.symfony-project.org/dependency-injection/trunk/ libro/01-dipendenza-iniezione

7
user1093284

Entrambi i modelli ottengono lo stesso effetto netto, fornendo un unico punto di accesso per le chiamate al database.

In termini di implementazione specifica, singleton ha un piccolo vantaggio di non avviare una connessione al database fino a quando almeno uno degli altri metodi non lo richiede. In pratica nella maggior parte delle applicazioni che ho scritto, questo non fa molta differenza, ma è un potenziale vantaggio se hai alcune pagine/percorsi di esecuzione che non fanno alcuna chiamata al database, dal momento che quelle pagine non lo faranno mai richiedere una connessione al database.

Un'altra differenza minore è che l'implementazione globale può calpestare involontariamente altri nomi di variabili nell'applicazione. È improbabile che tu possa mai dichiarare accidentalmente un altro riferimento globale $ db, anche se è possibile che tu possa sovrascriverlo accidentalmente (diciamo, scrivi if ($ db = null) quando intendevi scrivere if ($ db == null). L'oggetto singleton lo impedisce.

3
Adam Ness

Se non hai intenzione di usare una connessione persistente, e ci sono casi per non farlo, trovo che un singleton sia concettualmente più appetibile di un globale in OO design.

In un'architettura true OO, un singleton è più efficace della creazione di una nuova istanza dell'oggetto ogni volta.

2
Gavin M. Roy

Nell'esempio dato, non vedo alcun motivo per usare i singoli. Come regola generale, se la mia unica preoccupazione è quella di consentire una singola istanza di un oggetto, se il linguaggio lo consente, preferisco usare i globali

2
Dprado

In generale, userei un singleton per una connessione al database ... Non vuoi creare una nuova connessione ogni volta che devi interagire con il database ... Ciò potrebbe danneggiare le prestazioni e la larghezza di banda della tua rete ... Perché creare un uno nuovo, quando ce n'è uno disponibile ... Solo i miei 2 centesimi ...

RWendi

1
RWendi

È abbastanza semplice. Non usare mai global OR Singleton.

0
1800 INFORMATION

Come consiglio sia singleton che global sono validi e possono essere uniti all'interno dello stesso sistema, progetto, plugin, prodotto, ecc. ... Nel mio caso, realizzo prodotti digitali per il web (plugin).

Uso solo singleton nella classe principale e lo uso per principio. Quasi non lo uso perché so che la classe principale non lo creerà di nuovo

<?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");
    }
}

Globale uso per quasi tutte le classi secondarie, ad esempio:

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

mentre in fase di esecuzione posso usare Global per chiamare i loro metodi e attributi nella stessa istanza perché non ho bisogno di un'altra istanza della mia classe di prodotto principale.

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

Vedo che il globale è usare la stessa istanza per essere in grado di far funzionare il prodotto perché non ho bisogno di una factory per istanze della stessa classe, di solito la factory dell'istanza è per sistemi di grandi dimensioni o per scopi molto rari.

In conclusion:, se hai già capito bene che è l'anti-pattern Singleton e capisci Global, puoi usare una delle 2 opzioni o mescolarle ma se io consiglio di non abusare poiché ci sono molti programmatori che sono molto eccezionali e fedeli alla programmazione OOP, usalo per le classi principali e secondarie che usi molto nei tempi di esecuzione. (Ti fa risparmiare molta CPU). ????

0
Lenin Zapata