Domanda

Qual è il vantaggio dell'utilizzo di singleton anziché globale per le connessioni al database in PHP? Sento che usare singleton invece di global rende il codice inutilmente complesso.

Codice con globale

$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.

È stato utile?

Soluzione

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 il tipo di modifiche che verranno sollevate su di esso ad un certo punto in futuro, ma piuttosto che verrà apportata una qualche forma di modifica.

Renderlo un obiettivo attenuare il dolore 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?

Una fabbrica singleton 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 in seguito trasmessa 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?

Quello 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 "quotree 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 "codifica per domani oggi" è sempre una cosa cattiva non mi convince.

Altri suggerimenti

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. Obbligando le tue pagine a fare tutto il database connessioni in sequenza e uccisione qualsiasi tentativo di pagina asincrona carichi.

  2. Possibilmente trattenendo i blocchi aperti elementi del database più lunghi di necessario, rallentando nel complesso prestazioni del database.

  3. Massimizzando il numero totale di connessioni simultanee tuo il database può supportare e bloccare i nuovi utenti che accedono a 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 maggiori, 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 numerose 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, accadrà 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: nelle lingue .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.

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 basate su PHP di facile lettura relative all'iniezione di dipendenza (con esempi) su http://components.symfony-project.org/dependency-injection/trunk/book/01-Dependency-Injection

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

In termini di implementazione specifica, il 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 accidentalmente dichiarare 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.

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 design globale in OO.

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

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

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é crearne uno nuovo, quando ce n'è uno disponibile ... Solo i miei 2 centesimi ...

RWendi

È abbastanza semplice. Non usare mai OR globale Singleton.

Come consiglio sia singleton che globale 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 istanzerà più

<?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 utilizza 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 Globale 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();

Ottengo con il globale è usare la stessa istanza per poter 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 conclusione: , se hai già capito bene che è l'anti-pattern Singleton e capisci il Global , puoi usare una delle 2 opzioni o mescolarle, ma se 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 durante il tempo di esecuzione. (Ti fa risparmiare molta CPU). & # 128.521;

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top