Esiste un caso d'uso per i singoli con accesso al database in PHP?


138

Accedo al mio database MySQL tramite PDO. Sto configurando l'accesso al database e il mio primo tentativo è stato quello di utilizzare quanto segue:

La prima cosa a cui ho pensato è global:

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

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

Questa è considerata una cattiva pratica. Dopo una piccola ricerca, ho finito con il modello Singleton , che

"si applica alle situazioni in cui è necessario che vi sia un'unica istanza di una classe."

Secondo l'esempio nel manuale, dovremmo farlo:

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

Perché ho bisogno di quella classe relativamente grande quando posso farlo?

class Database {
    private static $db;

    private function __construct(){}

    static 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() {
    Database::get()->query('...');
}

some_function();

Quest'ultimo funziona perfettamente e non devo più preoccuparmi $db.

Come posso creare una classe singleton più piccola o esiste un caso d'uso per i singleton che mi manca in PHP?


Ci sono molte risorse e discussioni in questa domanda correlata: "Cosa c'è di così male nei single?"
FruitBreak,

Risposte:


80

Okay, mi sono chiesto per un po 'quando ho iniziato la mia carriera. Lo ha implementato in diversi modi e ha trovato due motivi per scegliere di non usare le classi statiche, ma sono piuttosto grandi.

Uno è che troverai molto spesso qualcosa di cui sei assolutamente sicuro di non avere mai più di un'istanza, alla fine ne avrai una seconda. Puoi finire con un secondo monitor, un secondo database, un secondo server - qualunque cosa.

Quando ciò accade, se hai usato una classe statica ti trovi in ​​un refactor molto peggio che se avessi usato un singleton. Un singleton è un modello iffy in sé, ma si converte abbastanza facilmente in un modello di fabbrica intelligente - può anche essere convertito per usare l'iniezione di dipendenza senza troppi problemi. Ad esempio, se il tuo singleton viene ottenuto tramite getInstance (), puoi facilmente cambiarlo in getInstance (databaseName) e consentire più database - nessuna altra modifica del codice.

Il secondo problema è il testing (e onestamente, questo è lo stesso del primo numero). A volte vuoi sostituire il tuo database con un database finto. In effetti questa è una seconda istanza dell'oggetto database. Questo è molto più difficile da fare con le classi statiche che con un singleton, devi solo deridere il metodo getInstance (), non ogni singolo metodo in una classe statica (che in alcune lingue può essere molto difficile).

Dipende davvero dalle abitudini - e quando la gente dice che i "Globali" sono cattivi, hanno ottime ragioni per dirlo, ma potrebbe non essere sempre ovvio finché non si risolve il problema da soli.

La cosa migliore che puoi fare è chiedere (come hai fatto tu), quindi fare una scelta e osservare le conseguenze della tua decisione. Avere le conoscenze per interpretare l'evoluzione del codice nel tempo è molto più importante che farlo nel modo giusto.


15
Dici che i singleton si degradano bene in DI, ma il tuo esempio non è getInstance(databaseName)ancora solo di spargere riferimenti a un repository globale di istanze in tutto il tuo codice? Il codice che chiamerebbe getInstancedovrebbe avere l'istanza (s) iniettata in esso dal codice client, e quindi non dovrebbe essere necessario chiamare getInstancein primo luogo.
Will Vousden

1
@Will Vousden Correct, è una specie di stop-gap. Non è davvero DI, ma può essere abbastanza vicino. Ad esempio, cosa succede se fosse getInstance (enabledDatabase) e l'istanza restituita è stata calcolata in base al database in cui è stato passato? Il punto è evitare di spaventare le persone con un framework DI fino a quando non sono pronte per questo.
Bill K,

320

I singleton hanno pochissimo - se non per dire no - l'uso in PHP.

Nelle lingue in cui gli oggetti vivono nella memoria condivisa, i Singleton possono essere usati per mantenere basso l'uso della memoria. Invece di creare due oggetti, fai riferimento a un'istanza esistente dalla memoria dell'applicazione condivisa a livello globale. In PHP non esiste tale memoria dell'applicazione. Un Singleton creato in una richiesta vive esattamente per quella richiesta. Un Singleton creato in un'altra Richiesta eseguita contemporaneamente è ancora un'istanza completamente diversa. Pertanto, uno dei due scopi principali di un Singleton non è applicabile qui.

Inoltre, molti degli oggetti che possono esistere concettualmente una sola volta nell'applicazione non richiedono necessariamente un meccanismo linguistico per imporlo. Se hai bisogno solo di un'istanza, non istanziarne un'altra . È solo quando potresti non avere nessun'altra istanza, ad esempio quando i cuccioli muoiono quando crei una seconda istanza, che potresti avere un caso d'uso valido per un Singleton.

L'altro scopo sarebbe quello di avere un punto di accesso globale a un'istanza all'interno della stessa richiesta. Sebbene ciò possa sembrare desiderabile, in realtà non lo è, perché crea un accoppiamento con l'ambito globale (come qualsiasi altro globale e statico). Ciò rende più difficile il test unitario e l'applicazione in generale meno gestibile . Esistono modi per mitigarlo, ma in generale, se è necessario disporre della stessa istanza in molte classi, utilizzare Iniezione dipendenze .

Guarda le mie diapositive per i Singleton in PHP - Perché sono cattivi e come puoi eliminarli dalle tue applicazioni per ulteriori informazioni.

Anche Erich Gamma , uno degli inventori del modello Singleton, dubita oggi di questo modello:

"Sono favorevole alla caduta di Singleton. Il suo uso è quasi sempre un odore di design"

Ulteriori letture

Se, dopo quanto sopra, hai ancora bisogno di aiuto per decidere:

Schema di decisione di Singleton


1
@Gordon sì. E anche se fosse possibile mantenere gli oggetti tra le richieste, Singleton viola ancora un paio di principi SOLID e introduce lo stato globale.
Gordon,

4
Mi dispiace andare contro il flusso, ma DI non è in realtà una soluzione al problema per cui viene utilizzato Singleton, a meno che tu non sia soddisfatto di avere classi con 42 parametri ctor (o 42 chiamate setFoo () e setBar () necessarie per farlo lavoro). Sì, purtroppo alcune app devono essere così accoppiate e dipendono da molte cose esterne. PHP è un linguaggio di colla e talvolta ci sono molte cose da incollare insieme.
StasM,

14
@StasM se hai 42 parametri del ctor o hai bisogno di molti setter, stai sbagliando. Guarda le discussioni sul codice pulito, per favore. Mi dispiace, se non posso preoccuparmi di spiegarlo ancora un'altra volta. Sentiti libero di chiedere nella chatroom di PHP per maggiori informazioni.
Gordon,

@Gordon Dov'è la chat room di php?
user658182

21

Chi ha bisogno di singoli in PHP?

Si noti che quasi tutte le obiezioni ai singoli derivano da punti di vista tecnici, ma sono anche MOLTO limitate nel loro campo di applicazione. Soprattutto per PHP. In primo luogo, elencherò alcuni dei motivi per utilizzare i singleton, quindi analizzerò le obiezioni all'utilizzo dei singleton. Innanzitutto, le persone che ne hanno bisogno:

- Le persone che stanno codificando un framework / codebase di grandi dimensioni, che verranno utilizzate in molti ambienti diversi, dovranno lavorare con framework / codebase diversi esistenti in precedenza, con la necessità di implementare molte richieste diverse, mutevoli e persino stravaganti da parte di clienti / capi / dirigenti / unità fanno.

Vedi, il modello singleton è auto-inclusivo. Al termine, una classe singleton è rigida su qualsiasi codice in cui la includi e si comporta esattamente come hai creato i suoi metodi e variabili. Ed è sempre lo stesso oggetto in una determinata richiesta. Dal momento che non può essere creato due volte per essere due oggetti diversi, sai qual è un oggetto singleton in un dato punto di un codice - anche se il singleton è inserito in due, tre diverse, vecchie, persino basi di spaghetti. Pertanto, rende più facile in termini di scopi di sviluppo - anche se ci sono molte persone che lavorano in quel progetto, quando vedi un singleton inizializzato in un punto in una data base di codice, sai cosa è, cosa fa, come e lo stato in cui si trova. Se fosse la classe tradizionale, dovresti tenere traccia di dove è stato creato l'oggetto, quali metodi sono stati invocati in esso fino a quel punto nel codice e il suo stato particolare. Ma lascia cadere un singleton lì, e se hai abbandonato i metodi di debug e informazioni e il monitoraggio nel singleton durante la codifica, sai esattamente di cosa si tratta. Quindi, rende più facile per le persone che devono lavorare con basi di codice diverse, con la necessità di integrare il codice che è stato fatto in precedenza con filosofie diverse o fatto da persone con cui non si ha alcun contatto. (vale a dire, fornitore-progetto-azienda-qualunque cosa non ci sia più, nessun supporto nulla). rende più facile per le persone che devono lavorare con basi di codice diverse, con la necessità di integrare il codice che è stato fatto in precedenza con filosofie diverse o fatto da persone con cui non si ha alcun contatto. (vale a dire, fornitore-progetto-azienda-qualunque cosa non ci sia più, nessun supporto nulla). rende più facile per le persone che devono lavorare con basi di codice diverse, con la necessità di integrare il codice che è stato fatto in precedenza con filosofie diverse o fatto da persone con cui non si ha alcun contatto. (vale a dire, fornitore-progetto-azienda-qualunque cosa non ci sia più, nessun supporto nulla).

- Persone che devono lavorare con API , servizi e siti Web di terze parti .

Se guardi più da vicino, questo non è troppo diverso dal caso precedente: API, servizi, siti Web di terze parti sono proprio come basi di codice isolate e esterne sulle quali NON hai controllo. Tutto può succedere. Quindi, con una sessione / classe utente singleton, puoi gestire QUALSIASI tipo di implementazione di sessione / autorizzazione da fornitori di terze parti come OpenID , Facebook , Twitter e molti altri - e puoi fare TUTTI allo stesso tempo dall'oggetto SAME singleton - che è facilmente accessibile, in uno stato noto in qualsiasi momento in qualunque codice lo si inserisca. Puoi persino creare più sessioni per più API / servizi di terze parti diversi per l'utente SAME nel tuo sito Web / applicazione e fare qualsiasi cosa tu voglia fare con loro.

Naturalmente, tutto ciò può anche essere tonificato con metodi tradizionali usando normali classi e oggetti: il problema è che singleton è più ordinato, più ordinato e quindi a causa di ciò gestibile / testabile più facile rispetto all'utilizzo tradizionale di classe / oggetto in tali situazioni.

- Le persone che hanno bisogno di fare un rapido sviluppo

Il comportamento globale dei singleton semplifica la creazione di qualsiasi tipo di codice con un framework che ha una raccolta di singleton su cui basarsi, perché una volta costruite bene le tue classi singleton, i metodi stabiliti, maturi e impostati saranno facilmente disponibili e utilizzabile ovunque, in qualsiasi momento, in modo coerente. Ci vuole un po 'di tempo per maturare le tue lezioni, ma dopo ciò sono solide, coerenti e utili. Puoi avere tutti i metodi in un singleton che fanno quello che vuoi e, sebbene ciò possa aumentare l'impronta di memoria dell'oggetto, porta molti più risparmi di tempo richiesti per un rapido sviluppo - un metodo che non stai usando in una determinata istanza di un'applicazione può essere utilizzata in un'altra integrata, e puoi semplicemente dare uno schiaffo a una nuova funzionalità che il client / capo / project manager richiede solo poche modifiche.

Ti viene l'idea. Ora passiamo alle obiezioni ai singoli e alla cattiva crociata contro qualcosa di utile :

- La principale obiezione è che rende i test più difficili.

E davvero, lo fa in una certa misura, anche se può essere facilmente mitigato prendendo le dovute precauzioni e codificando le routine di debug nei singoli con la consapevolezza che eseguirai il debug di un singleton. Ma vedi, questo non è troppo diverso da QUALSIASI altra filosofia / metodo / modello di codifica che è là fuori - è solo che, i singoli sono relativamente nuovi e non molto diffusi, quindi gli attuali metodi di test stanno comparando incompatibilmente con loro. Ma questo non è diverso in nessun aspetto dei linguaggi di programmazione: stili diversi richiedono approcci diversi.

Un punto in cui questa obiezione è piatta in quanto, ignora il fatto che le ragioni sviluppate dalle applicazioni non sono per il "test", e il testing non è l'unica fase / processo che va allo sviluppo di un'applicazione. Le applicazioni sono sviluppate per l'uso in produzione. E come ho spiegato nella sezione "Chi ha bisogno di singoli", i singoli possono tagliare un GRANDE affare dalla complessità di dover far funzionare un codice CON e ALL'INTERNO molti diversi database / applicazioni / servizi di terze parti. Il tempo che può andare perso durante i test è il tempo guadagnato nello sviluppo e nella distribuzione. Ciò è particolarmente utile in questa era di autenticazione / applicazione / integrazione di terze parti: Facebook, Twitter, OpenID, molti altri e chissà cosa ci aspetta.

Sebbene sia comprensibile, i programmatori lavorano in circostanze molto diverse a seconda della loro carriera. E per le persone che lavorano in aziende relativamente grandi con dipartimenti definiti che curano software / applicazioni diverse e definite in modo confortevole e senza l'imminente castigo di tagli / licenziamenti del budget e la necessità che ne consegue di fare MOLTE cose con molte cose diverse in una moda economica / veloce / affidabile, i singoli non possono sembrare così necessari. E può anche essere fastidio / impedimento a ciò che hanno già.

Ma per coloro che hanno bisogno di lavorare nelle sporche trincee dello sviluppo 'agile', dovendo implementare molte richieste diverse (a volte irragionevoli) dal loro cliente / manager / progetto, i singoli sono una grazia salvifica per ragioni spiegate in precedenza.

- Un'altra obiezione è che la sua impronta di memoria è maggiore

Poiché esiste un nuovo singleton per ogni richiesta di ciascun client, questo potrebbe essere un'obiezione per PHP. Con singleton mal costruiti e usati, l'impronta di memoria di un'applicazione può essere maggiore se molti utenti sono serviti dall'applicazione in un dato punto.

Tuttavia, questo è valido per QUALSIASI tipo di approccio che puoi adottare durante la codifica delle cose. Le domande che dovrebbero essere poste sono: i metodi, i dati che sono conservati ed elaborati da questi singoli non sono necessari? Perché, se SONO necessari in molte delle richieste che sta ricevendo l'applicazione, allora anche se non si usano i singoli punti, tali metodi e dati saranno presenti nell'applicazione in un modo o nell'altro attraverso il codice. Quindi, tutto diventa una questione di quanta memoria risparmierai, quando inizializzi un oggetto di classe tradizionale 1/3 nell'elaborazione del codice e lo distruggi per 3/4 in esso.

Vedi, in questo modo, la domanda diventa piuttosto irrilevante - non dovrebbero esserci metodi non necessari, i dati conservati negli oggetti nel tuo codice in ogni caso - indipendentemente dal fatto che tu usi singleton o meno. Quindi, questa obiezione ai singoli diventa davvero esilarante in questo, ASSUNTA che ci saranno metodi non necessari, dati negli oggetti creati dalle classi che usi.

- Alcune obiezioni non valide come "rende impossibile / più difficile mantenere connessioni multiple al database"

Non riesco nemmeno a comprendere questa obiezione, quando tutto ciò che serve è mantenere più connessioni al database, selezioni multiple di database, query multiple di database, più set di risultati in un dato singleton, è semplicemente tenerli in variabili / array nel singleton fintanto che sono necessari. Questo può essere semplice come tenerli negli array, sebbene tu possa inventare qualunque metodo tu voglia usare per farlo. Ma esaminiamo il caso più semplice, l'uso di variabili e array in un dato singleton:

Immagina che il seguito sia all'interno di un singolo singleton del database:

$ this -> connections = array (); (sintassi errata, l'ho appena digitata in questo modo per darti l'immagine - la dichiarazione corretta della variabile è public $ connections = array (); e il suo utilizzo è $ this-> connections ['connectionkey'] naturalmente)

In questo modo è possibile configurare e mantenere più connessioni in qualsiasi momento in un array. E lo stesso vale per le query, i set di risultati e così via.

$ this -> query (QUERYSTRING, 'queryname', $ this-> connections ['particulrconnection']);

Che può semplicemente fare una query su un database selezionato con una connessione selezionata e archiviarlo nel tuo

$ questo -> risultati

array con la chiave "nome query". Ovviamente, dovrai codificare il tuo metodo di query per questo, il che è banale da fare.

Ciò consente di mantenere un numero virtualmente infinito di (quanto i limiti delle risorse ovviamente consentono) diverse connessioni al database e set di risultati tanto quanto è necessario. E sono disponibili per QUALSIASI pezzo di codice in un dato punto in una data base di codice in cui questa classe singleton è stata istanziata.

Naturalmente, dovresti naturalmente liberare i set di risultati e le connessioni quando non sono necessari, ma questo è ovvio, e non è specifico per i singleton o qualsiasi altro metodo / stile / concetto di codifica.

A questo punto, puoi vedere come puoi mantenere più connessioni / stati verso applicazioni o servizi di terze parti nello stesso singleton. Non così diverso.

Per farla breve, alla fine, i modelli singleton sono solo un altro metodo / stile / filosofia con cui programmare, e sono utili come QUALUNQUE altro quando vengono usati nel posto giusto, nel modo giusto. Che non è diverso da qualsiasi cosa.

Noterai che nella maggior parte degli articoli in cui i singoli vengono colpiti, vedrai anche riferimenti a "globi" che sono "malvagi".

Ammettiamolo: TUTTO ciò che non viene usato correttamente, abusato, abusato, È malvagio. Ciò non si limita a nessuna lingua, nessun concetto di codifica, alcun metodo. Ogni volta che vedi qualcuno che rilascia dichiarazioni coperte come "X is evil", scappa da quell'articolo. È molto probabile che sia il prodotto di un punto di vista limitato - anche se il punto di vista è il risultato di anni di esperienza in qualcosa di particolare - che generalmente finisce per essere il risultato di lavorare troppo in un determinato stile / metodo - tipico conservatorismo intellettuale.

Per questo si possono dare infiniti esempi, che vanno da "i globi sono cattivi" agli "iframe sono cattivi". Circa 10 anni fa, persino proporre l'uso di un iframe in una data applicazione era un'eresia. Poi arriva Facebook, iframe ovunque, e guarda cosa è successo: gli iframe non sono più così malvagi.

Ci sono ancora persone che insistono ostinatamente sul fatto che sono "malvagie" - e talvolta anche per buone ragioni - ma, come puoi vedere, c'è bisogno, gli iframe soddisfano quel bisogno e funzionano bene, e quindi il mondo intero va avanti.

La principale risorsa di un programmatore / programmatore / ingegnere del software è una mente libera, aperta e flessibile.


2
-1. Anche se concordo sul fatto che avere una mente aperta e flessibile sia una risorsa indispensabile per qualsiasi sviluppatore, non riscatta Singleton dall'essere un Antipattern. La risposta di cui sopra contiene così tante dichiarazioni inesatte e conclusioni errate sulla natura e sugli effetti del Singleton che non posso fare a meno di ridimensionarlo.
Gordon

-1. Ho dovuto sperimentare un framework con molti singleton in prima persona e test automatici sono impossibili. Devo testare manualmente tutto tramite tentativi ed errori in un browser. Alcuni errori potrebbero essere prevenibili con la revisione del codice (ortografia, errori di sintassi) ma gli errori funzionali sono spesso nascosti. Questo test richiede molto più tempo rispetto ai test unitari. Con i test unitari potrei dire: questa classe funziona in modo isolato, l'errore deve essere altrove. Senza il debug è noioso.
Jim Martens,

Il framework doveva essere integrato nella registrazione e nel tracciamento degli errori. Inoltre, una classe che funziona correttamente in isolamento, funzionerebbe correttamente anche in forma singleton quando viene inserita in un'applicazione più ampia. Ciò significa che in quel caso ciò che sta rompendo sarebbe un'altra classe o funzione che interagisce con quel singleton. Questo non è diverso dal normale monitoraggio dei bug all'interno di una grande applicazione. Che è di per sé piuttosto difficile senza che l'applicazione abbia una registrazione adeguata.
Unity100

Imprecisa. Tonnellate di singletones è sicuramente MALE, perché crea Testing-HELL. :-) Tuttavia, un singolo per app può essere buono. Ad esempio: come funzionalità di registrazione unificata - da implementare in tutte le app (incluse alcune di codice legacy).
Filip OvertoneSinger Rydlo,

"Il tempo che potrebbe andare perso durante i test ..." Questa è una pratica e un modo di pensare davvero pessimi. Tutte quelle app legacy là fuori sono state sviluppate pensando a questo ed è diventato impossibile mantenerle, quindi avevano bisogno di essere riscritte. Se non ci sono test, il tempo verrà perso quando viene sviluppata una nuova funzionalità e si rompe qualcosa in qualche altra parte del sistema. Tempo perso durante il debug, tempo perso dagli utenti che possono utilizzare correttamente quella funzione, fiducia nell'app persa ecc.
bogdancep

15

I singleton sono considerati da molti come anti-schemi in quanto sono davvero solo glorificate variabili globali. In pratica ci sono relativamente pochi scenari in cui è necessario che una classe abbia solo un'istanza; di solito è sufficiente che un'istanza sia sufficiente , nel qual caso implementarla come singleton è completamente inutile.

Per rispondere alla domanda, hai ragione sul fatto che i singoli sono eccessivi qui. Una semplice variabile o funzione farà. Un approccio migliore (più solido), tuttavia, sarebbe quello di utilizzare l' iniezione di dipendenza per eliminare del tutto la necessità di variabili globali.


Ma i Singleton possono degradarsi molto facilmente in DI, le classi statiche non possono, il che è il vero problema con le classi statiche.
Bill K,

@Bill: È vero, ma è per questo che per prima cosa propongo un approccio DI, piuttosto che perdere funzioni o metodi statici :)
Will Vousden

In alcune lingue (come Java) le classi statiche (o i metodi statici delle classi) non possono essere estese. Quindi crei potenziali problemi (o, nella migliore delle ipotesi, più lavoro) per i futuri sviluppatori. Quindi alcuni suggeriscono che i metodi statici dovrebbero essere generalmente evitati a meno che tu non ne abbia una necessità specifica.
Marvo,

8

Nel tuo esempio hai a che fare con un singolo pezzo di informazioni apparentemente immutabili. Per questo esempio un Singleton sarebbe eccessivo e il solo utilizzo di una funzione statica in una classe andrà benissimo.

Altre riflessioni: potresti riscontrare un caso di implementazione di schemi per motivi di schemi e il tuo istinto ti sta dicendo "no, non devi" per i motivi che hai spiegato.

MA: Non abbiamo idea delle dimensioni e della portata del tuo progetto. Se si tratta di un codice semplice, forse da buttare via, che non è probabile che debba cambiare, sì, vai avanti e usa i membri statici. Ma, se pensi che il tuo progetto potrebbe dover essere ridimensionato o preparato per la manutenzione del codice lungo la strada, allora, potresti voler usare il modello Singleton.


1
Wow, semplicemente sbagliato. L'intero punto della differenza (la risposta alla domanda) è quanto sia più difficile correggere il codice in un secondo momento per aggiungere una seconda istanza. È molto più difficile farlo se si utilizzano metodi statici. Questo è come dire "Globals va bene nelle tue condizioni limitate" quando l'intero problema con Globals è che le condizioni cambiano.
Bill K,

@ Bill K: Sono d'accordo con te e userei un singleton se ci fosse qualche complessità. Ma stavo cercando di rispondere alla domanda dal punto di vista del PO e ho pensato, beh, sì, immagino sia eccessivo in questo caso molto limitato. Ovviamente stavo ignorando le preoccupazioni relative all'architettura o alla scalabilità e molte altre considerazioni. Avrei dovuto includerlo come avvertimento nella mia risposta, con una spiegazione sul perché qualcuno dovrebbe sempre usare un singleton ... che sicuramente avrebbe causato il downgrade degli altri?
Paul Sasik,

5

Innanzitutto, voglio solo dire che non trovo molti usi per il modello Singleton. Perché si vorrebbe mantenere un singolo oggetto completo nell'intera applicazione? Soprattutto per i database, cosa succede se desidero connettermi a un altro server di database? Devo disconnettermi e riconnetterlo ogni volta ...? Comunque...

Esistono diversi inconvenienti nell'uso dei globi in un'applicazione (che è ciò che fa l'uso tradizionale del modello Singleton):

  • Difficile al test unitario
  • Problemi di iniezione di dipendenza
  • Può creare problemi di blocco (applicazione multi-thread)

Utilizzare le classi statiche anziché un'istanza singleton fornisce anche alcuni degli stessi svantaggi, poiché il problema più grande di singleton è il getInstancemetodo statico .

Puoi limitare il numero di istanze che una classe può avere senza usare il getInstancemetodo tradizionale :

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

Questo aiuterà sui primi punti menzionati sopra: test unitari e iniezione di dipendenza; assicurandoti comunque che nella tua applicazione esista una sola istanza della classe. Ad esempio, potresti semplicemente passare l'oggetto risultante ai tuoi modelli (modello MVC) affinché possano utilizzarli.


5

Considera semplicemente come la tua soluzione differisce da quella presentata nei documenti PHP. In realtà, c'è solo una differenza "piccolo": la soluzione fornisce ai chiamanti della getter con un PDOesempio, mentre quello nella documentazione fornisce chiamanti Database::singletoncon un Databaseesempio (poi utilizzano il getter da quello di ottenere un PDOesempio).

Quindi quale conclusione arriviamo?

  • Nel codice della documentazione, i chiamanti ottengono Databaseun'istanza. La Databaseclasse può esporre (in effetti, dovrebbe esporre se stai andando a tutti questi problemi) un'interfaccia più ricca o di livello superiore rispetto PDOall'oggetto che avvolge.
  • Se si modifica l'implementazione per restituire un altro tipo (più ricco) di PDO, le due implementazioni sono equivalenti. Non ci sono guadagni da seguire dopo l'implementazione manuale.

Dal punto di vista pratico, Singleton è un modello piuttosto controverso. Questo principalmente perché:

  • È abusato. I programmatori alle prime armi Grok Singleton molto più facile di quanto non facciano Grok altri schemi. Continuano quindi ad applicare le loro nuove conoscenze ovunque, anche se il problema a portata di mano può essere risolto meglio senza Singleton (quando si tiene un martello, tutto sembra un chiodo).
  • A seconda del linguaggio di programmazione, l'implementazione di un Singleton in modo ermetico e senza perdite può rivelarsi un compito titanico (soprattutto se abbiamo scenari avanzati: un singleton che dipende da un altro singleton, singoli che possono essere distrutti e ricreati, ecc. ). Prova a cercare la "definitiva" implementazione di Singleton in C ++, ti sfido (possiedo il rivoluzionario Modern C ++ Design di Andrei Alexandrescu, che documenta gran parte del caos).
  • Impone un carico di lavoro aggiuntivo sia durante la codifica di Singleton sia durante la scrittura del codice per accedervi, carico di lavoro di cui è possibile fare a meno seguendo alcuni vincoli autoimposti su ciò che si tenta di fare con le variabili del programma.

Quindi, come conclusione finale: il tuo singleton va bene. Anche non usare Singleton va bene per la maggior parte del tempo.


2

La tua interpretazione è corretta. I singoli hanno il loro posto ma sono abusati. Spesso è sufficiente accedere alle funzioni dei membri statici (in particolare, quando non è necessario controllare il tempo di costruzione in alcun modo). Meglio, puoi semplicemente mettere alcune funzioni e variabili libere in uno spazio dei nomi.


2

Durante la programmazione non c'è "giusto" e "sbagliato"; c'è "buona pratica" e "cattiva pratica".

I singleton vengono generalmente creati come classe da riutilizzare in seguito. Devono essere creati in modo tale che il programmatore non provochi accidentalmente due istanze durante la codifica ubriaca a mezzanotte.

Se avete un po 'di classe semplice che non dovrebbe essere un'istanza più di una volta, non è necessario per renderlo un Singleton. Se lo fai, è solo una rete di sicurezza.

non è sempre una cattiva pratica avere oggetti globali. Se sai che lo utilizzerai a livello globale / ovunque / per tutto il tempo, potrebbe essere una delle poche eccezioni. Tuttavia, i globi sono generalmente considerati "cattive pratiche" nello stesso modo in cui gotosono considerate cattive pratiche.


2

Non vedo assolutamente nessun punto. Se la classe fosse implementata in modo tale che la stringa di connessione fosse presa come parametro per il costruttore e mantenesse un elenco di oggetti PDO (uno per ogni stringa di connessione univoca), forse ci sarebbe qualche vantaggio, ma l'implementazione di singleton in questa istanza sembra un esercizio inutile.


1

Non ti manca nulla, per quanto posso vedere. L'esempio è piuttosto imperfetto. Farebbe differenza, se la classe singleton avesse alcune variabili di istanza non statiche.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.