Das Singleton-Pattern (Implementierung in PHP)

Einführung
Wenn man verhindern will, dass es von einer Klasse mehrere Objekte gibt, behilft man sich mit dem sogenannten Singleton-Pattern.

Es merkt sich, ob bereits eine Instanz existiert und verweigert dann die Erzeugung einer neuen Instanz. Stattdessen wird die aktuelle zurückgegeben.

Das Pattern privatisiert den Konstruktor und verbietet das Klonen. Der Code sieht so aus:

Grundgerüst

class DasGibtsNurEinmal
{
    private static $instanz = false;

    public static function erzeuge()
    {
       if(self::$instanz === false)
       {
          self::$instanz = new self;
       }
       return self::$instanz;
    }

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

Der Konstruktor
Der Konstruktor wurde also als private deklariert, was verhindert, dass das Objekt per new-Operator erzeugt wird:

$gehtnicht = new DasGibtsNurEinmal;

Dieses Beispiel wirde eine Fehlermeldung erzeugen:

Fatal error: Call to private DasGibtsNurEinmal::__construct() from invalid context in C:\wamp\www\index.php on line 19

(Der Konstruktor darf nicht aus dem öffentlichen „Bereich“ ausgeführt werden)

Warum ist die Eigenschaft $instanz privat und statisch?
Weil sie immer für die Klasse verfügbar sein muss. Sie ist nicht an ein bestimmtes Objekt gebunden, sondern golt global für die ganze Klasse.

Warum ist erzeuge() statisch?
Die öffentliche Methode erzeuge() ist statisch, weil sie aufgerufen werden muss, wenn noch gar kein Objekt erstellt wurde. Sie kann also per Doppelpunktoperator aufgerufen werden.

Das Erzeugen einer Instanz
Mit der statischen Methode erzeuge() kann so die einzig mögliche Instanz erzeugt werden:

$objekt = DasGibtsNurEinmal::erzeuge();
var_dump($objekt);

Um zu sehen, dass das objekt erstellt wurde, verwenden wir var_dump(). Es gibt folgendes aus:

object(DasGibtsNurEinmal)#1 (0) { }

(Was soviel heißt wie: Erste Instanz von DasGibtsNurEinmal)

Beweis der Funktion unseres Patterns
Wenn wir jetzt weitere Versuche unternehmen, ein neues Objekt herzustellen, werden wir sehen, dass es immer bei #1 bleibt:

$objekt1 = DasGibtsNurEinmal::erzeuge();
var_dump($objekt1);
echo "\n";
$objekt2 = DasGibtsNurEinmal::erzeuge();
var_dump($objekt2);
echo "\n";
$objekt3 = DasGibtsNurEinmal::erzeuge();
var_dump($objekt3);
echo "\n";
$objekt4 = DasGibtsNurEinmal::erzeuge();
var_dump($objekt4);

Ausgabe:

object(DasGibtsNurEinmal)#1 (0) {
}

object(DasGibtsNurEinmal)#1 (0) {
}

object(DasGibtsNurEinmal)#1 (0) {
}

object(DasGibtsNurEinmal)#1 (0) {
}

Anhand der #1 sieht man, dass es sich immer um ein und dasselbe Objekt handelt.
Wenn man das jetzt immer noch nicht glaubt, kann man ja die statische Methode erzeuge() folgendermaßen abändern:

public static function erzeuge()
    {
       if(self::$instanz === false)
       {
          self::$instanz = new self;
          echo "Es existiert noch kein Objekt\n";
       }
       else
       {
	   echo "Es existiert schon ein Objekt\n";
       }
       return self::$instanz;
    }

Ergebnis:

Es existiert noch kein Objekt
Es existiert schon ein Objekt
Es existiert schon ein Objekt
Es existiert schon ein Objekt

Warum __clone() als private deklarieren?
Weil die Interzeptormethode __clone() sonst dazu verwendet werden könnte, eine Instanz zu klonen. So hätte man dann doch wieder 2 Objekte:

$objekt1 = DasGibtsNurEinmal::erzeuge();
$objekt2 = clone $objekt1;

Weil __clone() aber privat ist, sehen wir nur eine hübsche Warnung:

Fatal error: Call to private DasGibtsNurEinmal::__clone() from context “ in C:\wamp\www\index.php on line 25

Fazit
Es ist jetzt unmöglich, dass es mehr als eine Instanz von DasGibtsNurEinmal gibt.
Das könnte nützlich sein, wenn man z.B. eine Klasse hat, die für die Generierung von Meta-Tags o.Ä. zuständig ist. Denn hier braucht man normalerweise nur eine Instanz.

1 Star2 Stars3 Stars4 Stars5 Stars (2 Stimme, durchschnittlich 5,00 / 5)
Loading...


4 Kommentare zu “Das Singleton-Pattern (Implementierung in PHP)”

  1. […] Pattern, das man sehr häufig antrifft ist neben dem Singleton die sogenannte Registry. Eine Registry ist streng gesehen nur eine Verschiebung des globalen […]

  2. […] Ein Singleton muss es sein! Jetzt kommt noch der übliche Code für ein Singleton. […]

  3. […] habe __clone() bis jetzt noch nie verwendet, außer beim Singleton-Pattern zum Verhindern von zwei […]

  4. […] Zugang zu den Sessiondaten über eine Singleton-Klasse […]

Hinterlasse einen Kommentar!

Time limit is exhausted. Please reload the CAPTCHA.

»Informationen zum Artikel

Autor: Simon
Datum: 07.08.2008
Zeit: 21:31 Uhr
Kategorien: OOP & Design Patterns
Gelesen: 13332x heute: 4x

Kommentare: RSS 2.0.
Diesen Artikel kommentieren oder einen Trackback senden.

»Meta