PHP Blogger

Startseite Schreib mir ne Mail! RSS Abo Webnews

Ein generisches Singleton

Ein sehr beliebter (und oft über Google gefundener) Artikel bisher ist “Das Singleton Design Pattern mit PHP 4“. Das Grundprinzip des Artikels ist mit einem Satz erklärt: Eine beliebige Klasse bekommt die Funktion “getInstance” implementiert, die eine Referenz auf ein Objekt dieser Klasse zurückliefert.

Auf diese Art und Weise wird der Speicher geschont, weil zur Laufzeit immer nur eine einzige Objektinstanz verwendet wird. So kann man z.B. quer durch eine Applikation super einfach auf ein- und dieselbe Datenbankverbindung zugreifen.

Eigentlich wollte ich diesen Artikel nie veröffentlichen, es wird objektorientiert gesehen schon etwas gepfuscht und deshalb ist es nicht ganz korrekt - aber es klappt prima und deshalb möchte ich Euch meine Lösung nicht vorenthalten. Es kann ja jeder selbst entscheiden, ob er sie einsetzt oder nicht ;) Ich selbst hab es in nahezu allen meinen Projekt im Einsatz.

Die Grundidee ist natürlich dieselbe wie bei einem normalen Singleton - sonst wärs ja keins ;) Mit einer kleinen Spezialität: Die Funktion “getInstance” soll vererbbar sein. Damit z.B. folgendes funktioniert:

class Datenbankverbindung extends Singleton
{
  // Konkrete Implementierung...
}

Und natürlich auch

$db= Datenbankverbindung::getInstance();

Also das Ziel ist ganz klar. Nur nach ein paar Experimenten ist mir klar, das irgendwo so etwas wie

$obj= new $this();

machen müsste. Ist natürlich totaler Quatsch, weil $this bezieht sich nun mal schon auf ein konkretes Objekt, und das gibts in einer statischen Funktion nunmal nicht. Wie jetzt an den Klassennamen kommen? Ah, gibts da nicht Funktionen wie get_class oder eine Konstante namens __CLASS__?

Ja, die liefern aber immer nur den Klassennamen der Klasse zurück, die die Funktion implementiert. In unserem Fall wäre das “Singleton” - wir bräuchten aber “Datenbankverbindung”. Mist. Nach vielen Anläufen habe ich festgestellt, es gibt nur einen Weg, von jeder beliebigen Funktion eines Objektes an den Klassennamen des Objektes zu kommen: Die PHP Funktion “debug_backtrace“, welche den aktuellen Funktionsstack liefert.

Schnell eine kleine Hilfsfunktion geschrieben, die den Klassennamen ausliest und zurückliefert:

function _getClassName()
{
  $callers= debug_backtrace();
  return $callers[1]["class"];
}

Und die Funktion getInstance entsprechend erweitert:

function &getInstance()
{
  static $obj= null;
  if(!is_object($obj))
    $obj= eval("return new " . Singleton::_getClassName() . "();");
  return $obj;
}

Sieht insgesamt dann so aus:

<?php

class Singleton
{
  function &getInstance()
  {
    static $obj= null;
    if(!is_object($obj))
      $obj= eval("return new " . Singleton::_getClassName() . "();");
    return $obj;
  } 

  function _getClassName()
  {
    $callers= debug_backtrace();
    return $callers[1]["class"];
  }
}

?>

Man kann sich natürlich über den eval-Aufruf streiten. Wer das gar nicht mag, dem sei anstelle dessen folgendes empfohlen:

if(!is_object($obj))
{
  $cls= Singleton::_getClassName();
  $obj= new $cls();
}

Ähnliche Artikel:

  1. Hook- und Callback-Funktionen (Teil 1)
  2. PHP 5 Konstruktor unter PHP 4 einsetzen
  3. Die Mutter aller Objekte
  4. Hook- und Callback-Funktionen (Teil 3)

Schreib Deine Meinung