T-Rex: PHP: Singleton vs Static

Moin,

heute hätte ich da auch mal eine Meinungsfrage. 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. Da mein Schwerpunkt bislang vor allem bei Javascript lag hab ich nach einer Möglichkeit gesucht Singletons zu erschaffen in php. Hab dann schliesslich folgendes Basiskonstrukt gefunden:
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()
    {
    }
}

Der Aufruf wäre einmal so:
cSingleton::init()->machwas();
und einmal so
cStatic::machwas();

Meine Frage ist, welches von beiden besser ist?
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.

Gruß
Fabrikant
T-Rex

  1. Hoi,

    Meine Frage ist, welches von beiden besser ist?

    Kurz gesagt: Kommt drauf an. Wenn Du Interfaces, Polymorphie oder andere OOP-Spielereien nutzen möchtest, bist Du mit einem Singleton besser bedient. Andernfalls machen statische Methoden/Klassen mehr Sinn.

    Viele Grüße,
    Lukas

    1. Hi!

      Wenn Du Interfaces, Polymorphie oder andere OOP-Spielereien nutzen möchtest, bist Du mit einem Singleton besser bedient.

      An welche "anderen OOP-Spielereien" dachtest du da? Interfaces sind bei einem Singleton ohne Nutzen, Polymorphie dazu nicht kompatibel.

      Lo!

      1. Hey,

        Wenn Du Interfaces, Polymorphie oder andere OOP-Spielereien nutzen möchtest, bist Du mit einem Singleton besser bedient.

        An welche "anderen OOP-Spielereien" dachtest du da? Interfaces sind bei einem Singleton ohne Nutzen, Polymorphie dazu nicht kompatibel.

        Ein Singleton kann nicht von einer Elternklasse erben?
        Ein Singleton kann kein Interface implementieren?

        Das wär mir neu. Ist das in PHP so? Oder sprichst Du generell für die OOP?

        Viele Grüße,
        Lukas

        1. Hi!

          Ein Singleton kann nicht von einer Elternklasse erben?
          Ein Singleton kann kein Interface implementieren?

          Klassen können das. Und so kann das theoretisch eine Klasse, die das Singleton-Muster implementiert ebenfalls. Aber es wäre im Fall des Interfaces sinnlos. Wenn es nur eine Instanz geben darf, warum sollte sie dann ein Interface implementieren, was ja die Aufgabe hat, in mehreren verschiedenen Klassen, von denen wiederum Instanzen erzeugt werden können, ein gemeinsames Verhalten zu garantieren? Dann könnte man einfach eine Instanz einer anderen Klasse nehmen, womit die Einmaligkeit nicht mehr gegeben ist. Beim Erben ist es ähnlich. Die Einmaligkeit geht verloren, wenn man von einer Elternklasse einfach Instanzen erzeugen kann, die zumindest Teile des Kindverhaltens zur Verfügung stellen. Genauso ist es, wenn man von einer Singleton-Klasse erben kann.

          Das wär mir neu. Ist das in PHP so? Oder sprichst Du generell für die OOP?

          Das ist eine logische Einschränkung des Singleton-Patterns, damit es eben die Einmaligkeit sicherstellen kann.

          Lo!

          1. einfaches Beispiel:
            man hat eine Autoklasse welche die Methoden bremsen und lenken beinhaltet. Von dieser Leitet man nur einmal für ein spezielles Auto ab z.B. ein pinker Ferrari. Der kann dank der Ableitung bremsen und lenken, hat die Eigenschaft "pink" und es gibt ihn nur einmal - Singleton.
            Dann gibt es noch ein Auto dass fliegen kann. Da es sich um ein Prototyp handelt (also im technischen nicht im programmier Sinne), darf es von dem auch nur einen geben. Das Flugauto soll jedoch auch lenken und bremsen können.

            Also ich finde die Vererbung auch bei Singletons sinnvoll.

            das war mein Senf

            Gruß
            T-Rex'ton

            1. Hi!

              man hat eine Autoklasse welche die Methoden bremsen und lenken beinhaltet. Von dieser Leitet man nur einmal für ein spezielles Auto ab z.B. ein pinker Ferrari. Der kann dank der Ableitung bremsen und lenken, hat die Eigenschaft "pink" und es gibt ihn nur einmal - Singleton.

              Es gibt ihn nur einmal ist noch kein Singleton. Es darf ihn nur einmal geben wäre ein Singleton. Außerdem hat er die Eigenschaft "Farbe". "pink" wäre ein Inhalt dieser Eigenschaft.

              Wenn wesentliche Teile auch anderen zur Verfügung stehen, können die sich die Funktionalität nachbauen, womit der andere kein Einzelstück mehr und das Garantieversprechen des Singletons hinüber ist.

              Dann gibt es noch ein Auto dass fliegen kann. Da es sich um ein Prototyp handelt (also im technischen nicht im programmier Sinne), darf es von dem auch nur einen geben. Das Flugauto soll jedoch auch lenken und bremsen können.

              Dazu eignen sich die Methoden des Straßenfahrzeugs nicht. Mit den Rädern zu wackeln oder sie festzuklemmen bringt einem Flugauto wenig.

              Wie auch immer. Wichtiger als die genaue Defintion wäre die Frage, ob du überhaupt ein Singleton benötigst, beziehungsweise ob es nicht bessere Lösungswege gibt, die ohne die Nachteile des Singleton-Patterns auskommen.

              Lo!

  2. Hi!

    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.

    Die Frage ist, ob du wirklich sicherstellen musst, dass es nur eine einzige Instanz geben darf. Ansonsten ist es wenig sinnvoll, das Singleton-Pattern zu missbrauchen, wenn du nur eine Instanz brauchst. Du hast nur mehr Aufwand, das Singleton in jeder Klasse zu implementieren und ziehst gar keinen Nutzen aus seinen Eigenschaften. Weiterhin unterbindet es ziemlich wirkungsvoll ein sinnvolles automatisches Testen (TDD).

    Dem Gegenüber würden statische Klassen bzw. Methoden stehen.
    Meine Frage ist, welches von beiden besser ist?

    Entscheide, was besser ist: ein Objekt mit Eigenschaften und Methoden oder Funktionen und gegebenenfalls Variablen, die in einem "Namespace" liegen. Und kannst du diese Frage generell klären, dich daraufhin auf einen Weg beschränken oder willst du nicht lieber von Fall zu Fall entscheiden was sinnvoll ist?

    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.

    Ein Singleton ist etwas einzigartiges. Davon kann es weder Kinder, noch mehrere Instanzen, noch mal dies und mal das geben, sonst ist es kein Singleton mehr.

    Lo!

  3. Also so wie ich das sehe hast du im ersten Fall von der Klasse an sich keinen Nutzen. Du erzeugst ein Objekt von dem du nur die Methode nutzt, das kannst du mit static einfacher.
    Die Instanz wäre dann sinnvoll wenn du Variablen hast, die in der Instanz gehalten werden. Aber auch das würde statisch funktionieren.
    Singleton macht für mich dann Sinn, wenn du die Instanz irgendwoanders wieder übergeben musst, also wenn da ein Objekt übergeben werden soll.

    Aber wenns nur drum geht eine Funktion aufzurufen, ist was statisches sinnvoller. Durch das Erzeugen eines unnötigen Objekts verbrätst du ein paar Mikrosekunden, ein bisschen Speicher (ok das ist vielleicht verzeihbar) und hast komplizierteren Code, dessen Sinn niemand sieht weil du das Objekt an sich nirgends brauchst.

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