3 Caching
Webseiten, die auf PHP basieren, werden üblicherweise dynamisch generiert. In den meisten Fällen ist es nur leider so, dass die Seiten deutlich öfter berechnet werden, als das nötig wäre. Da kann es sehr ressourcenschonend sein, einmal generierte Daten zwischenzuspeichern.
Gehen wir von einem Telefonverzeichnis für eine Firma aus. Ist das Unternehmen nicht gerade ein Weltkonzern, werden sich die Namen und Telefonnummern nicht sekündlich ändern. Somit ist es überflüssig, die beinhalteten Daten bei jedem Aufruf aus der Datenbank auszulesen und die Seite neu zu generieren. Um die Systembelastung zu reduzieren, wäre es sicher ausreichend, die Seiten einmal am Tag zu generieren. An dieser Stelle kommen Cache-Pakete ins Spiel, die es Ihnen ermöglichen, die einmal generierten Daten zwischenzuspeichern. Wird eine Datei beim Server angefordert, prüft dieser also erst, ob die fertige Datei bereits gecacht ist. Ist das der Fall, sendet er sie direkt an den Client. Ist die Datei nicht vorhanden oder ist die gecachte Information bereits ungültig, wird die Seite neu erstellt, an den Client geschickt und im Cache abgelegt.
Bei der Arbeit mit Caches müssen Sie beachten, dass der Code, der zum Rendern einer Seite, zum Aufbau von Datenbankverbindungen, zum Öffnen von Dateien oder Ähnlichem notwendig ist, nur dann ausgeführt werden sollte, wenn das auch wirklich nötig ist – also nur dann, wenn die Seite neu berechnet werden muss.
3.1 Cache_Lite 

Besprochene Version: 1.3.1 | Lizenz: LGPL |
Klassendatei(en): Cache/Lite.php |
Fabien Martys Cache_Lite ist ein kleines, leicht zu nutzendes Paket. Zwar ist Cache_Lite nicht sehr flexibel, aber für viele Einsatzfälle ist es absolut ausreichend. Das Paket ist in der Datei Cache/Lite.php enthalten und definiert zwei Klassen. Zum Ersten ist das die Klasse Cache_Lite, deren Konstruktor ein assoziatives Array mit Optionen übergeben bekommen kann. Die Schlüssel mit den entsprechenden Erläuterungen finden Sie in Tabelle 3.1.
Bevor ich auf die eigentliche Funktionsweise eingehe, möchte ich noch ein paar Besonderheiten des Pakets erwähnen. Die Klasse unterstützt die Möglichkeit, Daten im RAM abzulegen. Das erscheint aber nur begrenzt sinnvoll, da die Daten nur dem Script zur Verfügung stehen, das sie auch erzeugt hat, da sie nicht im Shared Memory, sondern in einem Array abgelegt werden. Daher werde ich darauf nicht eingehen.
Des Weiteren ist die Fehlerbehandlung in diesem Paket ein wenig anders geregelt. Die meisten Pakete inkludieren die Klasse PEAR zum Error-Handling. In diesem Fall ist es allerdings so, dass PEAR nur dann inkludiert wird, wenn ein Fehler auftritt. Das erhöht die Performance, hat aber den Nachteil, dass Sie die Rückgabewerte einer Funktion nicht mithilfe von PEAR::isError() prüfen können. Auch erscheint das Überprüfen aller Rückgabewerte nicht wirklich sinnvoll, wenn Sie die Performance einer Applikation steigern wollen. Somit würde ich Ihnen empfehlen, zum Debuggen den pearErrorMode auf CACHE_LITE_ERROR_DIE zu stellen. Wenn die Applikation dann ausreichend getestet ist, nutzen Sie wieder CACHE_LITE_ERROR_RETURN, um das Fehlerverhalten zu steuern, und hoffen, dass kein Fehler mehr auftritt.
Ein kleines Anwendungsbeispiel finden Sie in Listing 3.1.
require_once('Cache/Lite.php'); // Eindeutige ID fuer die Cache-Datei $id = '123'; // Optionen zum Steuern des Caches $optionen = array( // Verzeichnis zum Speichern 'cacheDir' => './cache/', // 6 Stunden Gueltigkeit 'lifeTime' => 21600, // zum Debuggen einschalten 'pearErrorMode' =>CACHE_LITE_ERROR_DIE ); $Cache_Lite = new Cache_Lite($optionen); // Testen, ob die Daten im Cache vorhanden sind if (!$daten = $Cache_Lite->get($id)) { // Nein, Seite neu generieren // Hier wird die Seite neu berechnet, // und alle Daten landen in $daten. // Zum Testen wird nur die Uhrzeit gespeichert $daten=date("H:i:s"); // Daten im Cache speichern $Cache_Lite->save($daten,$id); } echo $daten;
Listing 3.1 Nutzung von Cache_Lite
Wie Sie in Listing 3.1 sehen können, benötigt das Paket eine eindeutige ID für jede Cache-Datei. Nach dem Ableiten eines neuen Objekts wird mithilfe der Methode get() versucht, die Cache-Datei einzulesen. Kann die Datei nicht gefunden werden oder ist ihr Inhalt inzwischen ungültig, liefert die Methode false zurück. In diesem Fall muss die Seite neu generiert werden. Alle Daten, die auf der Seite ausgegeben werden sollen, werden zuerst in einer Variablen zusammengefasst. Der Inhalt dieser Variable wird dann mithilfe der Methode save()abgespeichert, die als zweiten Parameter die ID übergeben bekommt. Die eigentlichen Daten werden dann erst in der letzten Zeile mit einem echo ausgegeben. Die beiden Methoden get() und save() unterstützen darüber hinaus noch einen weiteren Parameter, mit dem Cache-Dateien zu Gruppen zusammengefasst werden können. Dateien, die zu Gruppen zusammengefasst wurden, können dann z. B. gemeinsam gelöscht werden.
Da es teilweise ein wenig aufwändig ist, alle Daten in einer Variablen zu erfassen, unterstützt das Paket auch die Möglichkeit, Daten mithilfe des Output-Bufferings zu erfassen und dann zu speichern. Das hat den Vorteil, dass Sie die Daten wie gewohnt ausgeben können und das Paket sie automatisch für Sie erfasst.
require_once('Cache/Lite/Output.php'); // Setzen von $id und dem Array $optionen $Cache_Lite = new Cache_Lite_Output($optionen); // Testen, ob die Daten im Cache vorhanden sind, // und sie gegebenenfalls ausgeben if (!$Cache_Lite->start($id)) { // Nein, Seite neu generieren // Hier wird die Seite neu berechnet // und alle Daten werden direkt ausgegeben echo date("H:i:s"); // Buffering beenden und Daten speichern. $Cache_Lite->end(); }
Listing 3.2 Nutzung von Cache_Lite mit Ausgabe-Pufferung
Zur Nutzung der Ausgabe-Pufferung muss die Datei Cache/Lite/Output.php eingebunden werden. Der Konstruktor der Klasse heißt Cache_Lite_Output() und akzeptiert ein Array mit denselben Werten, die in Tabelle 3.1 beschrieben sind. Die Methode start() prüft, ob eine entsprechende Cache-Datei vorhanden ist. Sollte das der Fall sein, wird ihr Inhalt direkt ausgegeben. Andernfalls gibt die Methode den booleschen Wert false zurück und schaltet die Ausgabe-Pufferung ein. Das heißt, jede Ausgabe, die Sie an den Browser senden, wird nun gepuffert. In der letzten Zeile wird schließlich die Member-Funktion end() aufgerufen, die die gepufferten Daten einerseits zum Browser schickt und sie andererseits in einer Datei ablegt.
Beide Klassen unterstützen darüber hinaus das Löschen von bestehenden Cache-Dateien. Sie können entweder explizit eine Datei mit einer bestimmten ID mit der Methode remove() löschen, die die ID der Datei übergeben bekommt. Das kann hilfreich sein, wenn Sie das Erneuern einer Cache-Datei erzwingen wollen. Darüber hinaus ist clean() definiert. Wenn Sie diese Methode ohne Parameter aufrufen, werden alle Cache-Dateien gelöscht. Mit dem optionalen Parameter können Sie den Löschvorgang aber auch auf die Gruppe einschränken, deren Namen Sie übergeben.