Per __get() aufwändige Properties nur bei Bedarf generieren
Problem: Wir haben eine Eigenschaft einer Klasse, die wir äußerst selten benötigen, die aber wegen einem Datenbankaufruf relativ viel Performance braucht.Jeder Artikel (sogenannter "content") hier im CMS ist ein PHP der Klasse $content. Da das CMS mehrsprachen-fähig ist kann für jede installierte Sprache, auch eine separate Version des jeweiligen Artikels angelegt werden.
In phpBB (auf dem das CMS basiert) gibt es eine Tabelle mit allen installierten Sprachen.
Da es für die interne Verwaltung ist es eigentlich relativ irrelevant welche Sprachen alles installiert sind. Die Sprache wird bei jedem Content-Artikel mit in der DB gespeichert.
Nun... hin und wieder braucht man aber eben doch alle installierten Sprachen.
Die Klasse content hat also eine Property $language_ARY in der alle installierten Sprachen gespeichert sind. Entsprechend gibt es auch eine Methode load_languages() (protected) welche die Sprachen aus der Datenbank holt und das besagte Array mit Daten bestückt.
Möglichkeit 1
:Eigentlich nichts wildes. load_languages() kommt in den Konstruktur und is'.
Nachteil: Man verschwendet Performance, weil die Property nur sehr selten benötigt wird.
Möglichkeit 2
:Okay, dann schreiben wir uns einfach einen Getter, der überprüft ob das array schon geladen ist und es dann zurückgibt
Nachteil: Ich hasse getter. Meine Entwicklungsumgebung (PhpEd) zeigt die Properties eines Objektes beim Tippen automatisch an, das funzt bei Gettern nactürlich nicht
Möglichkeit 3
:Wir machen die Methode load_languages() einfach public und müssen die einfach jedes Mal aufrufen bevor wir auf die Eigenschaft $language_ARY zugreifen wollen...
Nachteil: Umständlich in der Verwendung und auch alles andere als sauber.
Aber PHP ist was OOP angeht langsam erwachsen geworden, daher gibt es viele nette kleine Funktionen, die einem das Leben leichter machen, insbesondere die magische funktion __get() (magic functions nennt man spezielle PHP-Funktionen, die man sich an seine Bedürfnisse anpassen kann).
__get() wird als Methode einer Klasse immer dann aufgerufen, wenn auf eine Property zugegriffen wird die nicht existiert
Beispiel für __get
- Code: Alles auswählen
class bla
{
public $blubb_INT;
function __get($property_name_STR)
{
switch($property_name_STR)
{
case blubb:
return $this->blubb_INT;
break;
}
trigger_error();
}
}
Das ist ein praktisches Beispiel aus dem Leben. Wir hier beschrieben benutze ich seit geraumer Zeit Variablen, welche den Typ als Namen beinhalten. $lso nicht mehr $blubb sondern heute nur noch $blubb_INT für einen Integer.
Wenn man nun seine eigenen Konventionen ändert, die Klassen anpasst, den Code aber trotzdem abwärtskompatibel halten will, hat man ein Problem. Man muss die Propertys (sinnloserweise) doppelt anlegen. Man kann aber eben auch einfach die besagte __get() Methode verwenden. Wenn Ihr also jemand mit $bla_OBJ->blubb auf die besagte Eigenschaft zugreifen will findet PHP die Eigenschaft natürlich nicht (weil sie umbenannt wurde) und ruft __get() auf welches dann die eigentlich gemeinte Property zurückliefert...
Doch zurück zu unserem Problem. Hier können wir uns genau diese Methode zu Nutze machen:
- Code: Alles auswählen
public function __get($property_name_STR)
{
//erstmal schauen ob der Parameter im Array vorhanden ist
switch($property_name_STR)
{
case language_ARY:
$this->language_ARY = array();
$this->language_ARY = $this->load_languages();
return $this->language_ARY;
break;
}
}
Die language_ARY habe ich hier natürlich nicht als Klassen-Eigenschaft angelegt (AUFSCHREI!!! ...ja ja ich weiß, aber das ist PHP und nicht C++ oder Java und genau hier liegt eben die Stärke), damit hier entsprechend die __get() Methode aufgerufen wird.
Greift man also per $content_OBJ->language_ARY bzw mit $this->language_ARY auf diese Eigenschaft zu, wird __get aufgerufen. Hier wird diese Property dann angelegt und mit Inhalten aus der Datenbank befüllt.
Da das Array allerdings jetzt als Objekteigenschaft existiert, wird bei einem zweiten Zugriff nun auch __get nicht mehr aufgerufen, sondern die Eigenschaft wird direkt zurückgegeben.
Best of both worlds
BBcode für diesen Artikel:
