PHP: Das Singleton-Pattern

Von Klassen kann man in der Regel beliebig viele Instanzen erstellen, um mehrere Objekte zu haben. Es gibt aber auch Fälle, wo man explizit nur eine einzige Instanz einer Klasse im gesamten Projekt haben sollte. Eine Datenbankklasse wäre da als Beispiel ganz gut. Würde man in jeder anderen Klasse ein neues Datenbankobjekt erzeugen, dann würden unnötige Datenbank-Verbindungen aufgebaut werden.

Wann wendet man das Singleton-Pattern an?

Um das oben beschriebene Problem zu verhindern, gibt es das Singleton-Pattern. Dieses Pattern lässt immer nur eine einzige Instanz einer Klasse zu, die man eine statische Methode der Klasse abrufen kann. So verhindert man, dass man dutzende Datenbankverbindungen aufbaut, obwohl man ja eigentlich nur eine Einzige braucht. Ein anderes Beispiel wäre eine Konfigurationsklasse. Von der braucht man im Normalfall eigentlich auch nur eine einzige Instanz.

Die Singleton-Klasse erstellen

Im folgenden Beispiel erstellen wir erst einmal das Klassen-Grundgerüst und setzen die magischen Methoden wie den Konstruktor und die Klon-Methode auf private. Das soll verhindern, dass man später nicht über das Schlüsselwort new doch noch eine neue Instanz erzeugen kann. Und klonen kann man die Klasse dann später auch nicht mehr, wenn __clone auf private gesetzt ist. Dann bauen wir noch die Methode getInstance ein, die einem immer die aktuelle Instanz zurückgibt.

class Singleton {
    private static $INSTANCE = NULL;

    private function __construct() {}
    private function __clone() {}

    public static function getInstance() {
        if(!self::$INSTANCE) {
            self::$INSTANCE = new self;
        }

        return self::$INSTANCE;
    }
}

Und damit wäre die Singleton-Klasse auch schon fertig. Der Konstruktor und die Klon-Methode werden auf private gesetzt, so dass man darüber nicht doch noch an eine neue Instanz kommen kann, und die statische Klassenmethode getInstance gibt einem immer die aktuelle Instanz der Klasse zurück.

Wenn noch keine Instanz erzeugt wurde, dann ist die statische Eigenschaft $INSTANCE gleich NULL und es wird mit new self eine neue erstellt. Danach ist die Instanz bereits erstellt und die Methode getInstance gibt immer die vorher erstellte Instanz der Klasse zurück.

Die Singleton-Klasse anwenden

Die Singleton-Klasse ist nun fertig und kann benutzt werden. Natürlich kann man jetzt beliebige Methoden und Eigenschaften wie in einer normalen Klasse dort definieren. Diese müssen auch nicht statisch sein.

Man kann auch dieses Prinzip auf fertige Klassen anwenden und muss einfach nur den Singleton dort reinschreiben und bei der Erstellung der Instanz die getInstance-Methode aufrufen. Zu Demonstrationszwecken erstelle ich jetzt einfach noch eine Methode, die den übergebenen String wieder zurückgibt.

public function getString($string) {
    if($string != '') {
        return $string;
    }
}

Und nun holen wir uns die Instanz und lassen einen String einfach wieder zurückgeben. Wenn man die Klasse nun innerhalb einer anderen Klasse braucht, dann kann man dann dort ebenfalls wieder eine Variable oder Eigenschaft mit der getInstance-Methode bestücken. Dann hat man nämlich kein neues Objekt erzeugt sondern, wie schon so oft jetzt gesagt, die aktuelle Instanz der Singleton-Klasse.

$str = 'Foo Bar Foo Bar Foo Bar';
$obj = Singleton::getInstance();
echo $obj->getString($str);

Warnung vor Abhängigkeiten vom PHP-Manual

Das Singleton-Pattern ist eines der kontrovers betrachteten Pattern. Kritiker argumentieren, dass Singletons zu globale Zuständen in Applikationen führen und dass sie das Singleton und die benutzenden Klassen eng koppeln. Somit entstehen versteckte Abhängigkeiten und unerwartete Seiteneffekte, woraus wiederum Code entsteht, der schwierig zu testen und zu warten ist.

Die Kritiker argumentieren außerdem, dass es sinnlos ist, ein Singleton in einer Shared-Nothing-Architektur wie PHP einzusetzen, in der Objekte nur innerhalb eines Requests eindeutig sind. Es ist einfacher und sauberer, Kollaborations-Objektgraphen zu erstellen, indem die Builder- und Factory-Pattern am Anfang eines Requests benutzt werden.

Singletons verstoßen außerdem gegen die "SOLID"-OOP-Design-Regeln und gegen das Gesetz von Demeter. Singletons können nicht serialisiert werden. Sie können nicht durch Subtypen ersetzt werden (vor PHP 5.3) und sie werden auch nicht bei der Garbage-Collection berücksichtigt, weil die Instanz als statisches Attribut des Singletons gespeichert wird.

Quelle: https://secure.php.net/manual/de/language.oop5.patterns.php

Hinweis:
Dies ist ein älterer Artikel von meinem alten Blog. Die Kommentare zu diesem Artikel werden (falls vorhanden) später noch hinzugefügt.

Der Autor

Unter dem Namen »TheBlackPhantom« alias »BlackY« veröffentlichte ich auf meinem alten Blog, BlackPhantom.DE, in der Zeit von 2011 bis 2015 leidenschaftlich Beiträge über Computer, Internet, Sicherheit und Malware. Während der BlackPhantom-Zeit war ich noch grün hinter den Ohren und lernte viel dazu. Mehr Infos vielleicht in Zukunft...