Ladezeit verbessern mit PHP Caching?
Jahr für Jahr wachsen nicht nur die Anforderungen an Webseiten, sondern auch die Besucherzahlen. Zusätzlich möchte man als Webseitenbetreiber seine Webseite schnell und einfach verwalten können. Genau das richtige Einsatzgebiet für Skriptsprachen wie PHP und Konsorten.
PHP - Ladezeit verbessern mit Caching?
Jahr für Jahr wachsen nicht nur die Anforderungen an Webseiten, sondern auch die Besucherzahlen. Zusätzlich möchte man als Webseitenbetreiber seine Webseite schnell und einfach verwalten können. Genau das richtige Einsatzgebiet für Skriptsprachen wie PHP und Konsorten.
Es gibt viele einfache und schnelle Wege eine Webseite skalierbar zu gestalten. Schwieriger wird es, wenn die Faktoren Verwaltungsaufwand und Geschwindigkeit dazukommen. Ich möchte heute mit diesem Beitrag auf den Faktor Geschwindigkeit eingehen.
Für PHP Applikationen gibt es eine Vielzahl von Tools, die die Ladezeit einer Seite verbessern können. Zunächst möchte ich ein paar etablierte Cache Systeme vorstellen.
Einige bekannte Cache Systeme:
Zend Optimizer (kostenpflichtig)
Der Zend Optimizer arbeitet mit vorkompilierten PHP Dateien, dadurch werden unter anderem Festplattenzugriffe verringert.
Der Zend Optimizer bietet unter anderem auch Code Verschlüsselung, was für eine Lizenzierung sehr hilfreich sein kann.
http://www.zend.com/products/server/
Memcache (OpenSource)
Ist ein Cache-Server der Daten im Arbeitsspeicher ablegt und ausliest. Memcache wird hauptsächlich für die Optimierung von zeitintensiven Datenbankabfragen genutzt. Dabei werden die Abfrage Ergebnisse gecached.
- Alternative PHP Cache – APC (OpenSource)
APC ist fast schon Standart wenn es um PHP-Cache Systeme geht. APC nutzt den PHP Bytecompiler und erzeugt vorkompilierten PHP Code welcher in einem gemeinsamen Speicher abgelegt wird.
http://pecl.php.net/package/APC
Smarty (OpenSource)
Smarty ist eigentlich kein Cache System, sondern vielmehr ein Template-System. Jedoch verfügt Smarty über ein Cache System, welches PHP Seiten in HTML übersetzt und dadurch die Skriptaufrufe verringert.
Anhand eines kleinen Beispiels möchte ich die prinzipielle Funktionsweise erklären.
Ausgangssituation:
Eine Liste mit dynamischen Spalten und Zeilen soll gecached werden. Damit die Ladezeit besser beobachten werden kann, habe ich einen Daten-Array mithilfe dieses Skripts angelegt:
data.php
$buffer = '
;
$row = '';
for ($i=1;$i<=1000;$i++) {
$buffer .= '$dataArray[] = array(';
$row = '';
for ($j=1;$j<=10;$j++) {
if ($row!='') $row .= ',';
$row .= $i+$j-1;
}
$buffer .= $row . ');';
}
$buffer .= '?>';
file_put_contents('data.php',$buffer);
echo 'back';
Die ersten Überlegungen zum Cache System:
Folgende Anforderungen soll unser kleines Cache System erfüllen:
- PHP Dateien sollen „gecached" werden können.
-Strings sollen „gecached" werden können
Das eigentliche Caching in unserem Beispiel soll PHP übernehmen. Dabei lassen wir uns eine Datei oder einen String durch PHP übersetzen und speichern die gepufferte Ausgabe in einer Datei. Bei jedem Aufruf wird geprüft ob bereits eine Cache Datei existiert und ob diese noch „aktuell" ist.
Hinweis: Die Aktualität einer Datei zu prüfen ist nicht ganz trivial, deswegen werden wir in diesem Beispiel den Cache in bestimmen Zeitintervallen erneuern lassen.
CacheHandler.class.php
/**
* CacheHandler.class.php
* Cache Example
*/
/**
* CLASS CacheHandler
*
* Der CacheHandler verwaltet alle Cache Resourcen und stellt
* Methoden zum hinzufuegen und loeschen von Cache Inhalten zur Verguegung.
*/
class CacheHandler {
/* Pfad fuer Cache Dateien */
public $cacheDir;
/* Array mit CacheResourcen */
public $cacheHandles = array();
/**
* @param - $cacheDir
* @return - CacheHandler Obj
*/
public function __construct($cacheDir='cache') {
$this->cacheDir = $cacheDir;
$this->templateDir = $templateDir;
}
/**
* String am Cache anmelden
* @param $resourceName - Variablenname fuer den String
* @param $content - Inhalt der Variablen
* @return - StringResource
*/
public function addString($resourceName,$content) {
return $this->cacheHandles[$resourceName] = new StringResource($content,$this->cacheDir);
}
/**
* Datei am Cache anmelden
* @param $fileName - Name der Quelldatei
* @param $filePath - Pfad zur Quelldatei
*/
public function addFile($fileName,$filePath) {
return $this->cacheHandles[$fileName] = new FileResource($filePath.DIRECTORY_SEPARATOR.$fileName,$this->cacheDir);
}
/**
* Loescht alle registrierten Cache-Dateien
* @return void
*/
public function clearCache() {
foreach ($this->cacheHandles as $cacheHandle)
if (is_file($cacheHandle->cacheFile))
unlink($cacheHandle->cacheFile);
}
}
/**
* ABSTRACT CLASS CacheResource
*
* Stellt alle grundlegenden Funktionen das Anlegen und erneuern der
* Cache-Dateien zur Verfuegung
*/
abstract class CacheResource {
/* Zeitintervall fuer die Cache-Ernerung in Sekunden */
public $cacheLifeTime = 900;
/* Cached-code Datei */
public $cacheFile;
/**
* Pruefen ob Cache Datei existiert und "aktuell" ist,
* ggf. cache Datei anlegen
* @return void
*/
public function display() {
if (!file_exists($this->cacheFile))
$this->cache();
include $this->cacheFile;
if ($__cache__time__-time()<0)
$this->cache();
}
/**
* Cache Datei mit Erstellungsdatum speichern
* (Die Variable $__cache__time__ wird spaeter für Abfrage benoetigt)
* @return void
*/
protected function saveBuffer($buffer) {
file_put_contents($this->cacheFile,'
.(time()+$this->cacheLifeTime).'; ?>'.$buffer);
}
public function setLifeTime($seconds) {
$this->cacheLifeTime = $seconds;
}
public function cache() {}
}
/**
* CLASS FileResource
*
* Uebernimmt uebersetzten und Puffern einer Quelldatei
* @implements - CacheResource
*/
class FileResource extends CacheResource {
private $fileRes;
public function __construct($fileRes,$cacheDir) {
$this->fileRes = $fileRes;
$this->cacheFile = $cacheDir.DIRECTORY_SEPARATOR.sha1($cacheDir.DIRECTORY_SEPARATOR.$fileRes).'.php';
}
public function cache() {
ob_start(array(&$this,'saveBuffer'));
include $this->fileRes;
ob_end_clean();
}
}
/**
* CLASS StringResource
*
* Uebernimmt uebersetzten und Puffern eines Strings
* @implements - CacheResource
*/
class StringResource extends CacheResource {
private $stringRes;
public function __construct($stringRes,$cacheDir) {
$this->stringRes = $stringRes;
$this->cacheDir = $cacheDir;
$this->cacheFile = $cacheDir.DIRECTORY_SEPARATOR . sha1($_SERVER['SCRIPT_NAME'].DIRECTORY_SEPARATOR.$stringRes).'.php';
}
public function cache() {
ob_start(array(&$this,'saveBuffer'));
echo $this->stringRes;
ob_end_clean();
}
}
Beispielausgaben PHP Chaching:
Ausgabe ohne Cache
example.php
define('PATH',__DIR__);
if (!file_exists(PATH.'/data.php')) die('Beispiel Datei fehlt. Datei generieren.');
$start = microtime(true);
/*----------------------------------------------------------------------*/
include 'filesources/header.php';
include 'filesources/table.php';
echo '
'.date("d.m.Y - H:i").'
';
include 'filesources/footer.php';
/*----------------------------------------------------------------------*/
echo microtime(true)-$start.' Sekunden verbraucht';
Ausgabe mit Cache
example_cache.php
define('PATH',__DIR__);
if (!file_exists(PATH.'/data.php')) die('Beispiel Datei fehlt. Datei generieren.');
$start = microtime(true);
/*----------------------------------------------------------------------*/
include 'CacheHandler.class.php';
$cache = new CacheHandler(PATH.'/cache');
$header = $cache->addFile('header.php',PATH.'/filesources');
$footer = $cache->addFile('footer.php',PATH.'/filesources');
$table = $cache->addFile('table.php',PATH.'/filesources');
$creationDate = $cache->addString('lastUpdate','
'.date("d.m.Y - H:i").'
');
$header->display();
$table->display();
$creationDate->display();
$footer->display();
/*----------------------------------------------------------------------*/
echo microtime(true)-$start.' Sekunden verbraucht';
Nachteile bei dem vorgestellten System:
-
„Das Puffern" der Ausgabe ist nicht besonders effizient.
-
die Dateien / Strings werden komplett übersetzt, es können somit keine Ausnahmen definiert werden
-
Dateien / Strings können nicht verschachtelt werden










