Moin!
heute hätte ich da auch mal eine Meinungsfrage.
Ich hätte da eine Reihe von Globalmeinungen, denen ich im begründeten Einzelfall durch ihr Gegenteil auch mal widersprechen könnte. ;)
Mein Projekt wächst und wächst und ich merke das ich viele Klassen habe, die nur einmal initialisiert werden. Also braucht man nur 1 Instanz dieser Klasse.
Es ist ein Unterschied, ob man zufällig nur eine Instanz braucht, oder ob es nur eine einzige Instanz geben darf.
Da mein Schwerpunkt bislang vor allem bei Javascript lag hab ich nach einer Möglichkeit gesucht Singletons zu erschaffen in php.
Singletons sind das Pattern, welches am allerhäufigsten mißverstanden und mißbraucht wird. Vermutlich, weil es das einfachste der Pattern ist und von allen, die mal von OOP und Pattern gehört haben, eingesetzt wird, weil "man das ja so macht". ;)
Hab dann schliesslich folgendes Basiskonstrukt gefunden:
Es gibt vermutlich einige Varianten des Singleton-Patterns unter PHP - in PHP 4 ist man da ja etwas eingeschränkter gewesen, und viele solche Konstrukte findet man mit Suchmaschinen ja immer noch...
Entscheidend ist halt, dass sich das Codekonstrukt wie ein Singleton verhält, d.h. die einzige gebildete Instanz in einer permanenten, global gültigen Variablen abspeichert und bei allen Zugriffen ab dem zweiten anstelle eines neu konstruierten Objekts zurückgibt.
class cSingleton
{
static private $objInstance = null;
private function __constuct() {}
private function __clone() {}
static public function init()
{
if(self::$objInstance == null) {
self::$objInstance = new self();
}return $objInstance;
}public function machwas()
{
}
}Dem Gegenüber würden statische Klassen bzw. Methoden stehen.
class cStatic
{
static public function machwas()
{
}
}
Singletons sind im Prinzip böse. Man kann ganz schwer Tests für Singletons schreiben, aber insbesondere kann man noch viel schwerer Tests für Code schreiben, der seinerseits Singletons benutzt.
Außerdem gibt es eigentlich nur ganz ganz wenige Dinge, die während der Lebenszeit eines Skriptes wirklich einzigartig sein müssen, von denen es nur eine einzige Instanz geben DARF.
Deshalb sollte man vom Standpunkt der Testbarkeit ausgehend Singletons im Prinzip vermeiden.
Dasselbe gilt, in einem etwas anderen Licht, auch für statische Methoden. Diese Methoden sind genauso unhandlich wie Singletons, machen Code, der sie seinerseits verwendet, genauso schlecht testbar, man möchte sie also im Prinzip ebenso meiden - in einem etwas geringeren Maße.
Ich persönlich setze statische Methoden ausschließlich in Factorys ein. Die Factory-Methode baut mir ein Konglomerat von einigen Low-Level-Objekten zu einem nutzbaren High-Level-Objekt zusammen - und nicht mehr. Die Bauvorschrift wird in abgewandelter Form in den Tests angewandt (hier werden Mock-Objekte für die Abhängigkeiten generiert), weshalb diese statischen Methoden sich absichtlich a) ausgelagert in einer eigenen Factory-Klasse befinden und b) ausschließlich Objekte zusammenstöpseln, aber ansonsten nichts tun.
Insbesondere enthält die Klasse, die das eigentliche Nutzobjekt enthält, keinerlei Code, der dieses Objekt nutzbringend erzeugt. Denn die Klasse soll nur den Code enthalten, der die Aufgabe dieser Klasse erledigt - das Herstellen einer arbeitsfähigen Instanz der Klasse ist nicht die Aufgabe der Klasse selbst, sondern Aufgabe der zugehörigen Factory.
Der Aufruf wäre einmal so:
cSingleton::init()->machwas();
und einmal so
cStatic::machwas();Meine Frage ist, welches von beiden besser ist?
Beides ist schlecht. :)
Ich empfinde die erste Lösung als besser, da man als init() Rückgabe wert theoretisch eine andere Instanz zurückgeben könnte z.B. cSingletonChild. Also eine Fabrik.
Wenn die Methoden cSingleton::init() und cSingleton::machwas() existieren, ist das blöd, verstößt gegen mein oben dargelegtes Prinzip.
Wenn du eine Klasse mit Singleton-Eigenschaften schaffen willst, dann könntest du etwas weniger strikt vorgehen, indem du im Produktivcode die Verwaltung der einzigen Instanz in der Factory-Klasse erledigts, alternativ auch das Registry-Pattern anwendest (Registry ist das schöngefärbte Singleton, es ist aus Testbarkeitssicht auch nicht toll, aber etwas weniger böse).
Allerdings solltest du vorher wirklich mal intensiv diskutieren, für welche Objekte es wirklich unverzichtbar ist, dass ihre Einzigartigkeit garantiert ist. In PHP ist diese Diskussion vor allem auch in dem Licht zu betrachten, dass Einzigartigkeit jeweils nur pro Skriptaufruf gilt, parallele Skripte also sowieso in Parallelwelten agieren und voneinander nichts wissen. Diese grundsätzliche Architektur von PHP weicht den Singletongedanken schon sehr weit auf, denn ein Singleton existiert damit dann eben nur noch pro Skriptaufruf einmal, aber pro Zeiteinheit eben doch potentiell mehrfach.
Außerdem ist in die Diskussion einzuflechten, dass PHP seinerseits diverse Mechanismen eingebaut hat, um in der Kommunikation mit externen Systemen schon Singletonartigkeit zu implementieren. Beispiel: Der Klassiker für Singleton ist der Datenbankzugriff. DB "gibts nur eine", also ist die DB-Klasse ein Singleton. Spart bei Mehrfachinstanzierung (bzw. -sversuchen) den mehrfachen Aufbau der DB-Connection. Macht aber unmöglich, bei Bedarf auf multiple Datenbanken umzustellen, und ist außerdem unnötig, denn PHP filtert Aufbau der DB-Connection mit gleichen Parametern schon und verwendet für den zweiten Versuch die bereits bestehende Connection.
Das bedeutet im Endeffekt: Während man z.B. in Java ein Singleton einsetzen könnte, um darüber den Zugriff auf eine einzelne externe Ressource (z.B. Datei) zu kapseln, weil das Singleton dann eigenständig das Locking für Lesen und Schreiben intern implementieren könnte, wird das in PHP nicht funktionieren, weil Singleton keine globale Einzigartigkeit herstellt.
- Sven Rautenberg