Mini Caching Class

Flex

(aka Felix Jacobi)
So, da ich mich in letzter Zeit ein wenig mit Caching befasst habe, wollte ich mich nun dransetzen und meine erste eigene Caching Klasse erstellen...

Sie funktioniert, allerdings bin ich noch nicht ganz zufrieden...
Vielleicht hat ja der ein oder andere hier noch ein paar Verbesserungsvorschläge ;)
Kritik ist also voll erwünscht.

Version 0.7
flexcache.class.php
PHP:
<?php
/**
 * a simple Class for FileCaching
 */

class FlexCache {
	
	protected $_cache_lifetime;
	protected $_cache_file;
	
	public function __construct($config = array(), $section) 
	{
		$this->_cache_lifetime = $config['lifetime'];
		$this->_cache_file = $config['path'].$section;
		
		header("Expires: " . gmdate("D, d M Y H:i:s", time() + $this->_cache_lifetime) . " GMT");
		header("Cache-Control: max-age=".$this->_cache_lifetime."\n");

		ob_start();		
		if($this->checkCache() !== false) {
			$this->getCache();
			exit;
		}
	}
	protected function _createCache() 
	{
		@file_put_contents($this->_cache_file, ob_get_contents(), LOCK_EX);
	}
	public function getCache() 
	{
		print(@file_get_contents($this->_cache_file));
	}
	public function checkCache() 
	{
		if(  @file_exists($this->_cache_dir.$this->_section) === true 
				&& @filemtime($this->_cache_file) >= (time() - $this->_cache_lifetime))
		{ 
			return true;
		}
		else 
		{
			return false;
		}
	}	
	public function cache()
	{
		$this->_createCache();
		ob_end_flush();
	}
}
?>

example.php
PHP:
<?php

require_once("./flexcache.php");

$config['path'] = "./tmp/";
$config['lifetime'] = "10"; // 1h in seconds

$cache = new flexcache($config, "index");

$conn = mysqli_connect("localhost", "root", "", "test");

$sql = mysqli_query($conn, "SELECT id, title, `desc`, created FROM `benchmark`");

while($row = mysqli_fetch_assoc($sql)) {
  echo date("d-m-Y", $row['created'])." - ".$row['title']."<br>";
  echo $row['desc']."<br>";
}

$cache->cache();
?>

So ganz zufrieden bin ich mit dem Aufruf noch nicht, aber spontan fiel mir da keine andere Lösung für ein, wegen der Verwendung der Output Buffering Funktionen.
 
Zuletzt bearbeitet:
Hi

du solltest auf jeden Fall die beiden Konstanten, die du im Konstruktor definierst (CACHE_DIR und CACHE_LIFETIME) durch entsprechende Klassenvariablen ersetzen, da man sont nur ein Objekt der Cache Klasse erstellen kann, da man sonst bei allen weiteren Malen eine Fehlermeldung erhält, weil die Konstanten schon definiert sind.

Alternativ könntest du die Konstanten ja auch vorher mit defined() prüfen, damit sie nur beim ersten Erstellen der Cache Klasse definiert werden, diese Lösung lässt dann aber halt immer nur eine Einstellung für Verzeichnis und Lifetime zu.

PS: Schön zu sehen, dass es auch Leute gibt, die PHP5 nutzen :)
 
Hi

du solltest auf jeden Fall die beiden Konstanten, die du im Konstruktor definierst (CACHE_DIR und CACHE_LIFETIME) durch entsprechende Klassenvariablen ersetzen, da man sont nur ein Objekt der Cache Klasse erstellen kann, da man sonst bei allen weiteren Malen eine Fehlermeldung erhält, weil die Konstanten schon definiert sind.
Sehr gute Idee, ist gemacht. ;)
PS: Schön zu sehen, dass es auch Leute gibt, die PHP5 nutzen :)

gophp5.org ;)



Zur Klasse:
Habe ebenfalls in der createCache Funktion noch eine Erweiterung gemacht, so dass sie auch den Ordner für die Sektion erstellt, falls dieser noch nicht vorhanden ist. Aktualisierte Version kommt morgen früh.
 
@EvilO: Kann sein das ich mich irre, aber eine Caching-Klasse braucht man ja eigentlich nur einmal pro Aufruf, stimmts? Von daher ist das mit den defines zwar unschön, sollte aber problemlos funktionieren.

Eine Frage hab ich an dieser Stelle an Felix: Hat es einen bestimmten Grund, das createCache() protected deklariert ist?

Desweiteren würde mich ein Benchmark interessieren. Kannst du das evtl. noch bewerkstelligen?

Ansonsten super Sache!
 
Eine Frage hab ich an dieser Stelle an Felix: Hat es einen bestimmten Grund, das createCache() protected deklariert ist?
Weil ich nicht wollte, dass man von außen sozusagen die Funktion aufrufen kann, da sie gebunden ist an die Ausgabe von den Funktionen zur Ausgabesteuerung.

Desweiteren würde mich ein Benchmark interessieren. Kannst du das evtl. noch bewerkstelligen?
Werde ich die Tage noch machen.
Aufgebaut habe ich das ganze lose nach einem Blogeintrag:
krath.dk - Caching with PHP
Wobei ich da eher noch meine eigenen Benchmarks anstrebe, auch wenn ich darin noch etwas unerfahren bin.

Ansonsten super Sache!
Danke ;)
 
@saftmeister: Je nach Verwendung, hast du natürlich Recht, dass die Klasse nur einmal verwendet wird. Allerdings kann es ja auch sein, dass man seine Homepage modular aufbaut, und dann z.B. statt der gesamten Ausgabe, nur die Ausgabe der einzelnen Module cached, also etwa Menü, News, usw. In diesem Fall könnten durchaus mehrer Instanzen der Cacheklasse erzeugt werden, evtl. halt auch mit anderen Einstellungen für Verzeichnis und Lifetime, insofern macht es denke ich schon Sinn, dafür Variablen zu verwenden. ;)

@Felix Jacobi: Ich hätte da noch 2 kleine Vorschläge:

1. Du könntest die Funktion createCache() noch ein wenig umschreiben, um dir diese fopen() Geschichte zu vereinfachen, etwa so:
PHP:
    protected function createCache() 
    {
        if(!file_exists("./".$this->cache_dir."/".$this->section."/")) 
            mkdir("./".$this->cache_dir."/".$this->section."/");
        if(false === @file_put_contents("./".$this->cache_dir."/".$this->section."/".time(), ob_get_contents(), LOCK_EX)
        {
            // Fehlermeldung ausgeben mittels trigger_error() oder halt throw Exception(), falls du Exceptions verwendest.
        }
    }

2. (Schlage ich vor, weil ich es so mache, und es sich als sehr praktisch und übersichtlich erwiesen hat ;)) Du könntest protected und private Variablen und Funktionen mit einem Unterstrich (_) beginnen, ( etwa so: protected $_section; ) damit man sie, egal wo sie benutzt werden, direkt als protected / private erkennt.

Ich hoffe, dass das nicht zu viel Klugbeisserei war. :)
 
Nein, im Gegenteil ;)

Wollte ich keine Kritik, hätte ich die Klasse gar nicht erst geposted.

An file_put_contents hatte ich gar nicht gedacht... Damned, vereinfacht natürlich einiges.

Das mit den geschützten und privaten Variablen, also diese extra zu kennzeichnen, habe ich glaube ich schlicht und einfach vergessen... Hatte ich ebenfalls bemerkt als ich mich mit dem Zend Framework auseinander gesetzt habe.

An Exceptions habe ich gedacht, aber wollte eher dazu übergehen einfach ein false wiederzugeben, damit die Seite nicht abbricht, sondern dann einfach die nicht gecachte Seite geladen wird und ein error.log angelegt wird.

Mal schauen wie ich das noch realisiere.
 
So, dann lasse ich mal Version 0.5 raus.

Die Klasse wurde noch einmal umgeschrieben und sollte auch keine Errors mehr werfen.
Falls ein Fehler auftritt, sollte trotzdem der Inhalt angezeigt werden und abgearbeitet werden.

Als nächstes kommt die Implementation von Exceptions, die dann in einer log File gespeichert werden.

deprecated

Der Aufruf wurde ebenfalls verändert, da nun bei einem Error während des Cache Lesens einfach aus dem switch ausgebrochen werden kann, während dies bei einer If Bedingung leider nicht geht. Deshalb dieser Pseudoswitch implementiert.
 
Zuletzt bearbeitet:
Es wäre sinnvoll HTTP Caching zu integrieren, so dass die Inhalte auch auf dem Client- oder einem Proxy-Cache zwischengespeichert werden können. Das würde vor allem die zu übertragende Datenmenge verringern.
Auch wäre es schön, wenn nur eine Instanz der Klasse erzeugt werden müsste und diese dann den Rest übernähme.
 
Zurück