Gibt es einen Anwendungsfall für Singletons mit Datenbankzugriff in PHP?


138

Ich greife über PDO auf meine MySQL-Datenbank zu. Ich richte den Zugriff auf die Datenbank ein und habe zunächst versucht, Folgendes zu verwenden:

Das erste, woran ich dachte, war global:

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

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

Dies wird als schlechte Praxis angesehen. Nach einer kleinen Suche kam ich zu dem Singleton-Muster , das

"Gilt für Situationen, in denen eine einzelne Instanz einer Klasse vorhanden sein muss."

Nach dem Beispiel im Handbuch sollten wir dies tun:

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

Warum brauche ich diese relativ große Klasse, wenn ich das kann?

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

Letzteres funktioniert perfekt und ich muss mir keine Sorgen $dbmehr machen.

Wie kann ich eine kleinere Singleton-Klasse erstellen oder gibt es einen Anwendungsfall für Singletons, die mir in PHP fehlen?


In dieser verwandten Frage gibt es viele Ressourcen und Diskussionen: "Was ist so schlecht an Singletons?"
FruitBreak

Antworten:


80

Okay, ich habe mich eine Weile darüber gewundert, als ich meine Karriere begann. Es wurde auf verschiedene Arten implementiert und es gab zwei Gründe, keine statischen Klassen zu verwenden, aber sie sind ziemlich groß.

Eine ist, dass Sie sehr oft etwas finden, von dem Sie absolut sicher sind, dass Sie nie mehr als eine Instanz haben werden, Sie haben schließlich eine zweite. Möglicherweise haben Sie einen zweiten Monitor, eine zweite Datenbank, einen zweiten Server - was auch immer.

Wenn Sie in diesem Fall eine statische Klasse verwendet haben, steht Ihnen ein viel schlechterer Refactor bevor, als wenn Sie einen Singleton verwendet hätten. Ein Singleton ist an sich ein zweifelhaftes Muster, das sich jedoch relativ leicht in ein intelligentes Factory-Muster konvertieren lässt. Es kann sogar ohne allzu großen Aufwand für die Verwendung der Abhängigkeitsinjektion konvertiert werden. Wenn Ihr Singleton beispielsweise über getInstance () abgerufen wird, können Sie dies ganz einfach in getInstance (databaseName) ändern und mehrere Datenbanken zulassen - keine weiteren Codeänderungen.

Das zweite Problem ist das Testen (und ehrlich gesagt ist dies das gleiche wie das erste Problem). Manchmal möchten Sie Ihre Datenbank durch eine Scheindatenbank ersetzen. Tatsächlich ist dies eine zweite Instanz des Datenbankobjekts. Dies ist mit statischen Klassen viel schwieriger als mit einem Singleton. Sie müssen nur die Methode getInstance () verspotten, nicht jede einzelne Methode in einer statischen Klasse (was in einigen Sprachen sehr schwierig sein kann).

Es kommt wirklich auf Gewohnheiten an - und wenn Leute sagen, dass "Globals" schlecht sind, haben sie sehr gute Gründe, dies zu sagen, aber es ist möglicherweise nicht immer offensichtlich, bis Sie das Problem selbst getroffen haben.

Das Beste, was Sie tun können, ist zu fragen (wie Sie es getan haben), dann eine Wahl zu treffen und die Auswirkungen Ihrer Entscheidung zu beobachten. Das Wissen, die Entwicklung Ihres Codes im Laufe der Zeit zu interpretieren, ist viel wichtiger, als es überhaupt richtig zu machen.


15
Sie sagen, dass Singletons sich gut zu DI verschlechtern, aber ist Ihr Beispiel nicht getInstance(databaseName)immer noch das Verteilen von Verweisen auf ein globales Repository von Instanzen in Ihrem Code? Der Code, der aufgerufen werden getInstancesoll , sollte die Instanz (en) vom Client-Code einfügen und sollte daher nicht an getInstanceerster Stelle aufgerufen werden müssen .
Will Vousden

1
@ Will Vousden Richtig, es ist eine Art Lücke. Es ist nicht wirklich DI, aber es kann ziemlich nah sein. Was wäre zum Beispiel, wenn es getInstance (SupportedDatabase) wäre und die zurückgegebene Instanz basierend auf der übergebenen Datenbank berechnet würde? Es geht darum zu vermeiden, Menschen mit einem DI-Framework zu erschrecken, bis sie dazu bereit sind.
Bill K

320

Singletons haben in PHP sehr wenig - wenn nicht gar nein - Verwendung.

In Sprachen, in denen Objekte im gemeinsam genutzten Speicher gespeichert sind, können Singletons verwendet werden, um die Speichernutzung gering zu halten. Anstatt zwei Objekte zu erstellen, verweisen Sie auf eine vorhandene Instanz aus dem global freigegebenen Anwendungsspeicher. In PHP gibt es keinen solchen Anwendungsspeicher. Ein in einer Anfrage erstellter Singleton lebt für genau diese Anfrage. Ein Singleton, der in einer anderen gleichzeitig erstellten Anforderung erstellt wurde, ist immer noch eine völlig andere Instanz. Somit ist einer der beiden Hauptzwecke eines Singleton hier nicht anwendbar.

Darüber hinaus erfordern viele der Objekte, die konzeptionell nur einmal in Ihrer Anwendung vorhanden sein können, nicht unbedingt einen Sprachmechanismus, um dies zu erzwingen. Wenn Sie brauchen nur eine Instanz, dann tun instanziiert nicht eine andere . Nur wenn Sie möglicherweise keine andere Instanz haben, z. B. wenn Kätzchen beim Erstellen einer zweiten Instanz sterben, haben Sie möglicherweise einen gültigen Anwendungsfall für einen Singleton.

Der andere Zweck wäre, einen globalen Zugriffspunkt auf eine Instanz innerhalb derselben Anforderung zu haben. Dies mag zwar wünschenswert klingen, ist es aber nicht, da es eine Kopplung an den globalen Bereich schafft (wie alle globalen und statischen Elemente). Dies erschwert Unit-Tests und Ihre Anwendung ist im Allgemeinen weniger wartbar. Es gibt Möglichkeiten, dies zu mildern. Wenn Sie jedoch in vielen Klassen dieselbe Instanz benötigen, verwenden Sie im Allgemeinen die Abhängigkeitsinjektion .

Weitere Informationen finden Sie in meinen Folien für Singletons in PHP - Warum sie schlecht sind und wie Sie sie aus Ihren Anwendungen entfernen können.

Sogar Erich Gamma , einer der Erfinder des Singleton-Musters, bezweifelt dieses Muster heutzutage:

"Ich bin dafür, Singleton fallen zu lassen. Seine Verwendung ist fast immer ein Designgeruch."

Weiterführende Literatur

Wenn Sie nach dem oben Gesagten noch Hilfe bei der Entscheidung benötigen:

Singleton-Entscheidungsdiagramm


1
@ Gordon ja. Und selbst wenn es möglich war, Objekte zwischen Anfragen zu verwalten, verstoßen Singletons immer noch gegen einige SOLID-Prinzipien und führen Global State ein.
Gordon

4
Es tut uns leid, gegen den Fluss zu gehen, aber DI ist keine wirkliche Lösung für das Problem, für das Singleton verwendet wird, es sei denn, Sie geben sich damit zufrieden, dass Klassen mit 42 ctor-Parametern (oder 42 setFoo () - und setBar () -Aufrufen erforderlich sind, um dies zu tun Arbeit). Ja, einige Apps müssen leider so gekoppelt sein und hängen von vielen externen Dingen ab. PHP ist eine Klebesprache, und manchmal gibt es viele Dinge, die zusammengeklebt werden müssen.
StasM

14
@StasM Wenn Sie 42 ctor-Parameter haben oder viele Setter benötigen, machen Sie es falsch. Sehen Sie sich bitte die Clean Code Talks an. Entschuldigung, wenn ich nicht die Mühe habe, dies noch ein anderes Mal zu erklären. Fragen Sie im PHP-Chatroom nach weiteren Informationen.
Gordon

@ Gordon Wo ist der PHP-Chatraum?
user658182

21

Wer braucht Singletons in PHP?

Beachten Sie, dass fast alle Einwände gegen Singletons aus technischer Sicht kommen - aber sie sind auch in ihrem Umfang SEHR begrenzt. Speziell für PHP. Zuerst werde ich einige Gründe für die Verwendung von Singletons auflisten und dann die Einwände gegen die Verwendung von Singletons analysieren. Erstens Menschen, die sie brauchen:

- Personen, die ein großes Framework / eine große Codebasis codieren, die in vielen verschiedenen Umgebungen verwendet werden, müssen mit zuvor vorhandenen, unterschiedlichen Frameworks / Codebasen arbeiten, wobei viele verschiedene, sich ändernde, sogar skurrile Anforderungen von Kunden / Vorgesetzten implementiert werden müssen / Management / Referatsleiter tun.

Das Singleton-Muster ist in sich geschlossen. Wenn Sie fertig sind, ist eine Singleton-Klasse für jeden Code, in den Sie sie aufnehmen, starr und verhält sich genau so, wie Sie ihre Methoden und Variablen erstellt haben. Und es ist immer das gleiche Objekt in einer bestimmten Anfrage. Da es nicht zweimal als zwei verschiedene Objekte erstellt werden kann, wissen Sie, was ein Singleton-Objekt an einem bestimmten Punkt in einem Code ist - selbst wenn der Singleton in zwei, drei verschiedene, alte, sogar Spaghetti-Codebasen eingefügt wird. Dies erleichtert die Entwicklung - selbst wenn in diesem Projekt viele Personen arbeiten, wissen Sie, was ein Singleton ist, was er tut und wie er funktioniert, wenn Sie sehen, dass ein Singleton an einem Punkt in einer bestimmten Codebasis initialisiert wird Wenn es sich um die traditionelle Klasse handelt, müssen Sie nachverfolgen, wo das Objekt zuerst erstellt wurde. welche Methoden darin bis zu diesem Punkt im Code aufgerufen wurden, und sein besonderer Zustand. Wenn Sie jedoch einen Singleton dort ablegen, und wenn Sie beim Codieren die richtigen Debugging- und Informationsmethoden und das Tracking im Singleton abgelegt haben, wissen Sie genau, was es ist. Dies erleichtert Menschen, die mit unterschiedlichen Codebasen arbeiten müssen, die Integration von Code, der zuvor mit unterschiedlichen Philosophien erstellt wurde, oder von Personen, mit denen Sie keinen Kontakt haben. (das heißt, Anbieter-Projekt-Unternehmen-was auch immer gibt es nicht mehr, keine Unterstützung nichts). Dies erleichtert es Menschen, die mit unterschiedlichen Codebasen arbeiten müssen, mit der Notwendigkeit, Code zu integrieren, der früher mit unterschiedlichen Philosophien erstellt wurde, oder von Personen, mit denen Sie keinen Kontakt haben. (das heißt, Anbieter-Projekt-Unternehmen-was auch immer gibt es nicht mehr, keine Unterstützung nichts). Dies erleichtert es Menschen, die mit unterschiedlichen Codebasen arbeiten müssen, mit der Notwendigkeit, Code zu integrieren, der früher mit unterschiedlichen Philosophien erstellt wurde, oder von Personen, mit denen Sie keinen Kontakt haben. (das heißt, Anbieter-Projekt-Unternehmen-was auch immer gibt es nicht mehr, keine Unterstützung nichts).

- Personen, die mit APIs , Diensten und Websites von Drittanbietern arbeiten müssen .

Wenn Sie genauer hinschauen, unterscheidet sich dies nicht allzu sehr von dem früheren Fall - APIs, Dienste und Websites von Drittanbietern sind wie externe, isolierte Codebasen, über die Sie KEINE Kontrolle haben. Alles kann passieren. Mit einer Singleton-Sitzung / Benutzerklasse können Sie also JEDE Art von Sitzungs- / Autorisierungsimplementierung von Drittanbietern wie OpenID , Facebook , Twitter und vielen mehr verwalten - und Sie können diese ALLE gleichzeitig über das gleiche Singleton-Objekt ausführen - die leicht zugänglich ist, in einem bekannten Zustand zu einem bestimmten Zeitpunkt in dem Code, in den Sie sie einstecken. Sie können sogar mehrere Sitzungen mit mehreren verschiedenen APIs / Diensten von Drittanbietern für den GLEICHEN Benutzer in Ihrer eigenen Website / Anwendung erstellen und mit ihnen alles tun, was Sie möchten.

Natürlich kann all dies auch mit herkömmlichen Methoden unter Verwendung normaler Klassen und Objekte abgeglichen werden - der Haken dabei ist, dass Singleton aufgeräumter und ordentlicher ist und daher im Vergleich zur herkömmlichen Verwendung von Klassen / Objekten in solchen Situationen leichter zu handhaben / zu testen ist.

- Menschen, die sich schnell entwickeln müssen

Das global ähnliche Verhalten von Singletons erleichtert das Erstellen von Code jeder Art mit einem Framework, das eine Sammlung von Singletons enthält, auf denen aufgebaut werden kann. Sobald Sie Ihre Singleton-Klassen gut erstellt haben, sind die etablierten, ausgereiften und festgelegten Methoden leicht verfügbar und verfügbar überall und jederzeit konsistent einsetzbar. Es dauert einige Zeit, um Ihre Klassen zu reifen, aber danach sind sie absolut solide und konsistent und nützlich. Sie können so viele Methoden in einem Singleton verwenden, wie Sie möchten. Dies erhöht zwar den Speicherbedarf des Objekts, spart jedoch viel mehr Zeit für eine schnelle Entwicklung - eine Methode, die Sie in einer bestimmten Instanz von nicht verwenden Eine Anwendung kann in einer anderen integrierten Anwendung verwendet werden, und Sie können einfach eine neue Funktion festlegen, die der Client / Chef / Projektmanager mit nur wenigen Änderungen anfordert.

Du hast die Idee. Kommen wir nun zu den Einwänden gegen Singletons und dem unheiligen Kreuzzug gegen etwas Nützliches :

- Der wichtigste Einwand ist, dass dies das Testen erschwert.

Und tatsächlich ist dies bis zu einem gewissen Grad der Fall, auch wenn es leicht gemildert werden kann, indem geeignete Vorsichtsmaßnahmen getroffen und Debugging-Routinen in Ihre Singletons codiert werden, mit der Erkenntnis, dass Sie einen Singleton debuggen werden. Aber sehen Sie, dies ist nicht zu verschieden von JEDER anderen Codierungsphilosophie / -methode / -muster, die es gibt - es ist nur so, dass Singletons relativ neu und nicht weit verbreitet sind, so dass die aktuellen Testmethoden mit ihnen vergleichsweise inkompatibel sind. Dies unterscheidet sich jedoch in keinem Aspekt der Programmiersprachen - unterschiedliche Stile erfordern unterschiedliche Ansätze.

Ein Punkt, bei dem dieser Einwand insofern unbegründet ist, als er die Tatsache ignoriert, dass die Gründe, aus denen Anwendungen entwickelt wurden, nicht für das „Testen“ sind und das Testen nicht die einzige Phase / der einzige Prozess ist, die in eine Anwendungsentwicklung einfließen. Anwendungen werden für den Produktionseinsatz entwickelt. Und wie ich im Abschnitt "Wer braucht Singletons?" Erklärt habe, können Singletons die Komplexität, einen Code mit und INNERHALB vieler verschiedener Codebasen / Anwendungen / Dienste von Drittanbietern funktionieren zu lassen, erheblich reduzieren. Die Zeit, die beim Testen verloren gehen kann, ist die Zeit, die bei der Entwicklung und Bereitstellung gewonnen wird. Dies ist besonders nützlich in Zeiten der Authentifizierung / Anwendung / Integration von Drittanbietern - Facebook, Twitter, OpenID, viele mehr und wer weiß, was als nächstes kommt.

Obwohl es verständlich ist, arbeiten Programmierer je nach Karriere unter sehr unterschiedlichen Umständen. Und für Leute, die in relativ großen Unternehmen mit definierten Abteilungen arbeiten und unterschiedliche, definierte Software / Anwendungen auf komfortable Weise und ohne das bevorstehende Schicksal von Budgetkürzungen / Entlassungen und die damit verbundene Notwendigkeit, eine Menge Dinge mit vielen verschiedenen Dingen zu erledigen, erledigen Eine billige / schnelle / zuverlässige Mode, Singletons scheinen nicht so notwendig zu sein. Und es kann sogar ein Ärgernis / Hindernis für das sein, was sie BEREITS haben.

Aber für diejenigen, die in den schmutzigen Gräben der "agilen" Entwicklung arbeiten müssen und viele verschiedene (manchmal unvernünftige) Anforderungen von ihrem Kunden / Manager / Projekt implementieren müssen, sind Singletons aus zuvor erläuterten Gründen eine Rettung.

- Ein weiterer Einwand ist, dass der Speicherbedarf höher ist

Da für jede Anforderung von jedem Client ein neuer Singleton vorhanden ist, kann dies ein Einwand für PHP sein. Bei schlecht konstruierten und verwendeten Singletons kann der Speicherbedarf einer Anwendung höher sein, wenn viele Benutzer zu einem bestimmten Zeitpunkt von der Anwendung bedient werden.

Dies gilt jedoch für JEDEN Ansatz, den Sie beim Codieren von Dingen verfolgen können. Die Fragen, die gestellt werden sollten, sind: Sind die Methoden, Daten, die von diesen Singletons gespeichert und verarbeitet werden, unnötig? Wenn sie für viele der Anforderungen erforderlich sind, die die Anwendung erhält, werden diese Methoden und Daten auch dann in Ihrer Anwendung in der einen oder anderen Form über den Code vorhanden sein, wenn Sie keine Singletons verwenden. Es wird also eine Frage, wie viel Speicher Sie sparen, wenn Sie ein traditionelles Klassenobjekt 1/3 in die Codeverarbeitung initialisieren und es 3/4 darin zerstören.

Auf diese Weise wird die Frage ziemlich irrelevant - es sollte KEINE unnötigen Methoden geben, Daten, die in Objekten in Ihrem Code enthalten sind - unabhängig davon, ob Sie Singletons verwenden oder nicht. Dieser Einwand gegen Singletons wird insofern sehr lustig, als davon ausgegangen wird, dass es unnötige Methoden und Daten in den Objekten gibt, die aus den von Ihnen verwendeten Klassen erstellt wurden.

- Einige ungültige Einwände wie "macht die Aufrechterhaltung mehrerer Datenbankverbindungen unmöglich / schwieriger"

Ich kann diesen Einwand nicht einmal verstehen, wenn alles, was man braucht, um mehrere Datenbankverbindungen, mehrere Datenbankauswahlen, mehrere Datenbankabfragen und mehrere Ergebnismengen in einem bestimmten Singleton aufrechtzuerhalten, sie nur in Variablen / Arrays im Singleton hält, solange sie werden gebraucht. Dies kann so einfach sein, wie sie in Arrays zu halten, obwohl Sie jede Methode erfinden können, die Sie verwenden möchten, um dies zu bewirken. Aber lassen Sie uns den einfachsten Fall untersuchen, die Verwendung von Variablen und Arrays in einem bestimmten Singleton:

Stellen Sie sich vor, das Folgende befindet sich in einem bestimmten Datenbank-Singleton:

$ this -> connection = array (); (falsche Syntax, ich habe es einfach so eingegeben, um Ihnen das Bild zu geben - die richtige Deklaration der Variablen lautet public $ connection = array (); und ihre Verwendung ist natürlich $ this-> connection ['connectionkey'])

Auf diese Weise können Sie mehrere Verbindungen gleichzeitig in einem Array einrichten und beibehalten. Gleiches gilt für Abfragen, Ergebnismengen usw.

$ this -> query (QUERYSTRING, 'queryname', $ this-> connection ['Participulrconnection']);

Das kann einfach eine Abfrage an eine ausgewählte Datenbank mit einer ausgewählten Verbindung durchführen und einfach in Ihrer speichern

$ this -> Ergebnisse

Array mit dem Schlüssel 'Queryname'. Natürlich müssen Sie dafür Ihre Abfragemethode codieren lassen - was trivial ist.

Auf diese Weise können Sie praktisch unendlich viele verschiedene Datenbankverbindungen und Ergebnismengen verwalten (sofern die Ressourcenbeschränkungen dies natürlich zulassen), so oft Sie sie benötigen. Und sie stehen JEDEM Code an einem bestimmten Punkt in einer bestimmten Codebasis zur Verfügung, in die diese Singleton-Klasse instanziiert wurde.

Natürlich müssten Sie natürlich die Ergebnismengen und Verbindungen freigeben, wenn sie nicht benötigt werden - aber das versteht sich von selbst und ist nicht spezifisch für Singletons oder andere Codierungsmethoden / -stile / -konzepte.

An diesem Punkt können Sie sehen, wie Sie mehrere Verbindungen / Status zu Anwendungen oder Diensten von Drittanbietern in demselben Singleton verwalten können. Nicht so anders.

Kurz gesagt, Singleton-Muster sind letztendlich nur eine andere Methode / Stil / Philosophie, mit der man programmieren kann, und sie sind genauso nützlich wie JEDE andere, wenn sie an der richtigen Stelle und auf die richtige Weise verwendet werden. Welches ist nicht anders als alles.

Sie werden feststellen, dass in den meisten Artikeln, in denen Singletons verprügelt werden, auch Hinweise darauf enthalten sind, dass "Globale" "böse" sind.

Seien wir ehrlich - ALLES, was nicht richtig benutzt, missbraucht, missbraucht wird, ist böse. Das ist nicht auf irgendeine Sprache, irgendein Kodierungskonzept, irgendeine Methode beschränkt. Wenn Sie jemanden sehen, der pauschale Aussagen wie "X ist böse" macht, laufen Sie vor diesem Artikel davon. Die Chancen stehen sehr hoch, dass es das Produkt einer eingeschränkten Sichtweise ist - auch wenn die Sichtweise das Ergebnis jahrelanger Erfahrung in etwas Bestimmtem ist -, was im Allgemeinen das Ergebnis einer zu starken Arbeit in einem bestimmten Stil / einer bestimmten Methode ist - einem typischen intellektuellen Konservatismus.

Dafür können endlose Beispiele angeführt werden, die von "Globals sind böse" bis zu "Iframes sind böse" reichen. Vor ungefähr 10 Jahren war es Häresie, sogar die Verwendung eines Iframes in einer bestimmten Anwendung vorzuschlagen. Dann kommt Facebook, iframes überall und schau, was passiert ist - iframes sind nicht mehr so ​​böse.

Es gibt immer noch Menschen, die hartnäckig darauf bestehen, dass sie "böse" sind - und manchmal auch aus gutem Grund -, aber wie Sie sehen, besteht ein Bedürfnis, wenn Iframes dieses Bedürfnis erfüllen und gut funktionieren, und deshalb bewegt sich die ganze Welt einfach weiter.

Das wichtigste Kapital eines Programmierers / Programmierers / Softwareentwicklers ist ein freier, offener und flexibler Geist.


2
-1. Ich stimme zwar zu, dass ein offener und flexibler Geist ein Muss für jeden Entwickler ist, aber es macht den Singleton nicht zu einem Antipattern. Die obige Antwort enthält so viele ungenaue Aussagen und falsche Schlussfolgerungen über die Natur und die Auswirkungen des Singleton, dass ich sie nur ablehnen kann.
Gordon

-1. Ich musste ein Framework mit vielen Singletons aus erster Hand erleben und ein automatisches Testen ist unmöglich. Ich muss alles manuell per Versuch und Irrtum in einem Browser testen. Einige Fehler können durch Codeüberprüfung vermieden werden (Rechtschreib-, Syntaxfehler), aber Funktionsfehler werden häufig ausgeblendet. Diese Tests erfordern viel mehr Zeit als Unit-Tests. Bei Unit-Tests könnte ich sagen: Diese Klasse arbeitet isoliert, der Fehler muss woanders liegen. Ohne das Debuggen ist das mühsam.
Jim Martens

Das Framework musste über Protokollierung und Fehlerverfolgung verfügen. Außerdem würde eine Klasse, die isoliert ordnungsgemäß funktioniert, auch in Singleton-Form ordnungsgemäß funktionieren, wenn sie in eine breitere Anwendung eingefügt wird. Was bedeutet, dass in diesem Fall eine andere Klasse oder Funktion, die mit diesem Singleton interagiert, kaputt geht. Dies unterscheidet sich nicht von der normalen Fehlerverfolgung in einer großen Anwendung. Was selbst ziemlich schwierig ist, ohne dass die Anwendung ordnungsgemäß protokolliert wird.
Unity100

Ungenau. Tonnenweise Singletones sind definitiv BÖSE, weil sie Testing-HELL erzeugen. :-) Aber man kann Singletone pro App gut sein. Zum Beispiel: als einheitliche Protokollierungsfunktion - zur Implementierung in allen Apps (einschließlich einiger Legacy-Code-Apps).
Filip OvertoneSinger Rydlo

"Die Zeit, die beim Testen verloren gehen kann ..." Dies ist eine wirklich sehr, sehr schlechte Praxis und Denkweise. Alle diese Legacy-Apps wurden unter diesem Gesichtspunkt entwickelt, und es wurde unmöglich, sie zu warten, sodass sie neu geschrieben werden mussten. Wenn es keine Tests gibt, geht die Zeit verloren, wenn eine neue Funktion entwickelt wird und etwas in einem anderen Teil des Systems kaputt geht. Zeitverlust beim Debuggen, Zeitverlust der Benutzer, die diese Funktion ordnungsgemäß nutzen können, Vertrauen in die verlorene App usw.
Bogdancep

15

Singletons werden von vielen als Anti-Muster angesehen, da sie wirklich nur verherrlichte globale Variablen sind. In der Praxis gibt es relativ wenige Szenarien , in denen es notwendig für eine Klasse nur eine Instanz zu haben; Normalerweise reicht nur eine Instanz aus . In diesem Fall ist die Implementierung als Singleton völlig unnötig.

Um die Frage zu beantworten, haben Sie Recht, dass Singletons hier übertrieben sind. Eine einfache Variable oder Funktion reicht aus. Ein besserer (robusterer) Ansatz wäre jedoch die Verwendung der Abhängigkeitsinjektion , um die Notwendigkeit globaler Variablen insgesamt zu beseitigen.


Aber Singletons können sehr reibungslos in DI zerfallen, statische Klassen nicht, was das eigentliche Problem bei statischen Klassen ist.
Bill K

@ Bill: Sehr wahr, aber deshalb würde ich zunächst einen DI-Ansatz befürworten, anstatt lose Funktionen oder statische Methoden :)
Will Vousden

In einigen Sprachen (z. B. Java) können statische Klassen (oder statische Methoden von Klassen) nicht erweitert werden. So schaffen Sie potenzielle Probleme (oder bestenfalls mehr Arbeit) für zukünftige Entwickler. Einige schlagen daher vor, statische Methoden generell zu vermeiden, es sei denn, Sie benötigen sie speziell.
Marvo

8

In Ihrem Beispiel handelt es sich um eine einzelne scheinbar unveränderliche Information. In diesem Beispiel wäre ein Singleton übertrieben und die Verwendung einer statischen Funktion in einer Klasse reicht völlig aus.

Weitere Gedanken: Möglicherweise haben Sie den Fall, dass Muster aus Gründen der Muster implementiert werden, und Ihr Bauch sagt Ihnen aus den von Ihnen genannten Gründen "Nein, das müssen Sie nicht".

ABER: Wir haben keine Ahnung von der Größe und dem Umfang Ihres Projekts. Wenn dies einfacher Code ist, vielleicht wegwerfen, der sich wahrscheinlich nicht ändern muss, dann ja, fahren Sie fort und verwenden Sie statische Elemente. Wenn Sie jedoch der Meinung sind, dass Ihr Projekt möglicherweise skaliert oder für die spätere Wartungscodierung vorbereitet werden muss, sollten Sie das Singleton-Muster verwenden.


1
Wow, einfach falsch. Der springende Punkt des Unterschieds (die Antwort auf die Frage) ist, wie viel schwieriger es ist, Ihren Code später zu reparieren, um eine zweite Instanz hinzuzufügen. Dies ist viel schwieriger, wenn Sie statische Methoden verwenden. Dies ist so, als würde man sagen "Globals sind unter Ihren begrenzten Bedingungen in Ordnung", wenn das gesamte Problem mit Globals darin besteht, dass sich die Bedingungen ändern.
Bill K

@ Bill K: Ich stimme Ihnen zu und würde einen Singleton verwenden, wenn es überhaupt Komplexität gäbe. Aber ich habe versucht, die Frage aus der Sicht des OP zu beantworten und dachte, nun ja, ich denke, es ist in diesem sehr begrenzten Fall übertrieben. Natürlich habe ich Architektur- oder Skalierbarkeitsprobleme und eine Menge anderer Überlegungen ignoriert. Hätte ich das als Einschränkung in meine Antwort aufnehmen sollen, zusammen mit einer Erklärung, warum jemand immer einen Singleton verwenden sollte ... was sicherlich zu Abstimmungen von anderen geführt hätte?
Paul Sasik

5

Zunächst möchte ich nur sagen, dass ich für das Singleton-Muster nicht viel Verwendung finde. Warum sollte man ein einzelnes Objekt in der gesamten Anwendung aufbewahren wollen? Was ist insbesondere bei Datenbanken, wenn ich eine Verbindung zu einem anderen Datenbankserver herstellen möchte? Ich muss jedes Mal die Verbindung trennen und wieder herstellen ...? Wie auch immer...

Die Verwendung von Globals in einer Anwendung hat mehrere Nachteile (wie dies bei der herkömmlichen Verwendung des Singleton-Musters der Fall ist):

  • Schwierig zu testen
  • Probleme mit der Abhängigkeitsinjektion
  • Kann Sperrprobleme verursachen (Multithread-Anwendung)

Die Verwendung statischer Klassen anstelle einer Singleton-Instanz bietet auch einige der gleichen Nachteile, da das größte Problem von Singleton die statische ist getInstance Methode ist.

Sie können die Anzahl der Instanzen einer Klasse begrenzen, ohne die herkömmliche getInstanceMethode zu verwenden:

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

Dies hilft bei den ersten oben genannten Punkten: Unit-Test und Abhängigkeitsinjektion; Stellen Sie dennoch sicher, dass in Ihrer Anwendung eine einzelne Instanz der Klasse vorhanden ist. Sie können beispielsweise das resultierende Objekt einfach an Ihre Modelle (MVC-Muster) übergeben, damit diese es verwenden können.


5

Überlegen Sie einfach, wie sich Ihre Lösung von der in den PHP-Dokumenten beschriebenen unterscheidet. Tatsächlich gibt es nur einen "kleinen" Unterschied: Ihre Lösung stellt Anrufern des Getters eine PDOInstanz zur Verfügung, während die Lösung in den Dokumenten Anrufern Database::singletoneine DatabaseInstanz zur Verfügung stellt (sie verwenden dann den Getter, um eine PDOInstanz abzurufen).

Zu welcher Schlussfolgerung kommen wir also?

  • Im Dokumentationscode erhalten Anrufer eine DatabaseInstanz. Die DatabaseKlasse kann eine umfangreichere oder übergeordnete Schnittstelle als das Objekt, das sie umschließt, verfügbar machen (tatsächlich sollte sie verfügbar sein , wenn Sie all diese Probleme haben) PDO.
  • Wenn Sie Ihre Implementierung so ändern, dass ein anderer (umfangreicherer) Typ als zurückgegeben wird PDO, sind die beiden Implementierungen gleichwertig. Es ist kein Gewinn, der manuellen Implementierung zu folgen.

Auf der praktischen Seite ist Singleton ein ziemlich kontroverses Muster. Dies liegt hauptsächlich daran, dass:

  • Es ist überbeansprucht. Anfänger programmieren Singleton viel einfacher als andere Muster. Anschließend wenden sie ihr neu gewonnenes Wissen überall an, auch wenn das vorliegende Problem ohne Singleton besser gelöst werden kann (wenn Sie einen Hammer halten, sieht alles wie ein Nagel aus).
  • Abhängig von der Programmiersprache kann sich die Implementierung eines Singletons in einer luftdichten, nicht undichten Weise als eine titanische Aufgabe erweisen (insbesondere wenn wir fortgeschrittene Szenarien haben: ein Singleton in Abhängigkeit von einem anderen Singleton, Singletons, die zerstört und neu erstellt werden können usw. ). Versuchen Sie einfach, nach "der endgültigen" Singleton-Implementierung in C ++ zu suchen, ich wage Sie (ich besitze Andrei Alexandrescus bahnbrechendes modernes C ++ - Design, das einen Großteil des Chaos dokumentiert).
  • Es führt zu einer zusätzlichen Arbeitslast, sowohl beim Codieren des Singleton als auch beim Schreiben von Code für den Zugriff darauf. Diese Arbeitslast können Sie vermeiden, indem Sie einige selbst auferlegte Einschränkungen für Ihre Programmvariablen befolgen.

Als letztes Fazit: Ihr Singleton ist in Ordnung. Singleton überhaupt nicht zu benutzen ist die meiste Zeit auch in Ordnung.


2

Ihre Interpretation ist richtig. Singletons haben ihren Platz, werden aber überbeansprucht. Oft ist der Zugriff auf statische Elementfunktionen ausreichend (insbesondere, wenn Sie die Bauzeit in keiner Weise steuern müssen). Besser, Sie können einfach einige freie Funktionen und Variablen in einen Namespace einfügen.


2

Beim Programmieren gibt es nicht "richtig" und "falsch"; Es gibt "gute Praxis" und "schlechte Praxis".

Singletons werden im Allgemeinen als Klasse erstellt, die später wiederverwendet werden soll. Sie müssen so erstellt werden, dass der Programmierer nicht versehentlich zwei Instanzen instanziiert, während er um Mitternacht betrunken codiert.

Wenn Sie eine einfache kleine Klasse haben, die nicht mehr als einmal instanziiert werden sollte , brauchen Sie sie nicht einen Singleton zu machen. Es ist nur ein Sicherheitsnetz, wenn Sie dies tun.

Es ist nicht immer schlecht, globale Objekte zu haben. Wenn Sie wissen, dass Sie es global / überall / jederzeit verwenden werden, kann dies eine der wenigen Ausnahmen sein. Globale werden jedoch im Allgemeinen als "schlechte Praxis" angesehen, genauso wie sie gotoals schlechte Praxis angesehen werden.


2

Ich sehe überhaupt keinen Grund dafür. Wenn Sie die Klasse so implementiert haben, dass die Verbindungszeichenfolge als Parameter für den Konstruktor verwendet wurde und eine Liste von PDO- Objekten verwaltet (eines für jede eindeutige Verbindungszeichenfolge), hat dies möglicherweise einen gewissen Vorteil, aber die Implementierung von Singleton in Diese Instanz scheint eine sinnlose Übung zu sein.


1

Sie vermissen nichts, soweit ich sehen kann. Das Beispiel ist ziemlich fehlerhaft. Es würde einen Unterschied machen, wenn die Singleton-Klasse einige nicht statische Instanzvariablen hätte.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.