Memcache: Cachen in PHP

Nachdem ich ja bereits eine kleine PHP Klasse veröffentlicht habe, um HTML mit PHP cachen zu können, jetzt natürlich auch noch die für große Projekte viel schönere Variante mit Memcache.
Anders als beim HTML-Caching lassen sich mit PHP Memcache Teile eines Programms in den Hauptspeicher verschieben.
Memcache wird in den meisten Systemen standardmäßig noch nicht mitgeliefert.
Wir müssen vor der Nutzung ggf. also erst noch Memcache installieren.

Für die einfachere Nutzung von Memcache habe ich mir wieder eine kleine PHP Klasse geschrieben:

<?php
/*
/
/ @class: MMCache
/ @desc: easy management of PHP Memcache
/ @author: Heiko Ramaker, www.web-skripte.de
/ @version: beta 1
/ @date: 2008/08/02
/
*/
class MMCache {

    
// default lifetime in seconds: 14 days
    
const DEFAULT_LIFETIME 1209600;
    
// connection port (normally 12111)
    
const DEFAULT_PORT 11211
    
// default memcache host
    
const DEFAULT_HOST '127.0.0.1';
    
// use persistant memcache connections
    
const USE_PCONNECT FALSE
    
// enable automatic compression of large values (needs the zlib)
    
const USE_AUTOMATIC_ZLIB FALSE
    
// automatic compression on values larger than 20000 bytes
    
const AUTOMATIC_ZLIB_SIZE 20000
    
// compression ratio (between 0 and 1), 0.5 means 50%
    
const AUTOMATIC_ZLIB_COMPRESSION 0.4;
    
// Use compression EVER on EACH value
    
const USE_ZLIB TRUE

    
    public 
$memcache// placeholder

    /*
    / automatic connect to memcache-server
    */
    
public function __construct(&$conf_arr null) {

        
$this->memcache = new Memcache;
        
$conf $this->checkConfig(&$conf_arr);

        if(
self::USE_PCONNECT === TRUE) {
            
$this->memcache->pconnect($conf['Host'], $conf['Port']);
        } else {
            
$this->memcache->connect($conf['Host'], $conf['Port']);
        }

        if(
self::USE_AUTOMATIC_ZLIB === TRUE) {
            $
$this->memcache->setCompressThreshold(self::AUTOMATIC_ZLIB_SIZEself::AUTOMATIC_ZLIB_COMPRESSION);
        }
    }

    
/*
    / check $conf_arr array if connection-data is complete
    */
    
private function checkConfig(&$conf_arr null) {

        if(!
is_array($conf_arr)) {
            
$conf_arr = (array)$cong_arr;
        }

        if(empty(
$conf_arr['Host'])) {
            
$host self::DEFAULT_HOST;
        } else {
          
$host $conf_arr['Host'];
        }
        if(empty(
$conf_arr['Port'])) {
            
$port self::DEFAULT_PORT;
        } else {
          
$port $conf_arr['Port'];
        }
        if(empty(
$conf_arr['Lifetime'])) {
            
$lifetime self::DEFAULT_LIFETIME;
        } else {
          
$lifetime $conf_arr['Lifetime'];
        }

        
$conf_arr = array('Host' => $host'Port' => $port'Lifetime' => $lifetime);

        return 
$conf_arr;

    }

    
/*
    / get a value by its key from the memcache server
    */
    
public function load($key) {

        
$result = array();

        if(!
is_array($key)) {
            
$key = (array)$key;
        }

        
// memcache only handles keys with max length of 250
        
if(strlen($key) > 250) {
            
$key md5($key);
        }

        
$result $this->memcache->get($key);
        if(
$result === FALSE) {
            return 
FALSE;
        } else {
            if(!
is_array($result)) {
                
$result = (array)$result;
            }
            return 
$result;
        }

    }

    
/*
    / save values as an array by given key
    */
    
public function save($key$val$compression null$lifetime null) {

        if(
is_null($compression)) {
            
$compression self::USE_ZLIB;
        }
        if(
is_null($lifetime)) {
            
$lifetime self::DEFAULT_LIFETIME;
        }

        if(!
is_array($val)) {
            
$val = (array)$val;
        }

        
// memcache only handles keys with max length of 250
        
if(strlen($key) > 250) {
            
$key md5($key);
        }

        if( 
$this->memcache->set($key$val$compression$lifetime) === TRUE ) {
            return 
TRUE;
        }

        return 
FALSE;

    }

    
/*
    / delete memcache-object by key. key could be either string oder array
    */
    
public function remove($key$time null) {

        if(!
is_array($key)) {
            
$key = (array)$key;
        }

        
$time = (int)$time// delete delayed

        
foreach($key as $num) {
            
$this->memcache->delete($num$time);
        }

    }

    
/*
    / get memcache stats
    */
    
public function getStats() {
        return 
$this->memcache->getExtendedStats();
    }


    public function 
__destruct() {
        
$this->memcache->close();
    }

}
?>


Memcache mit dieser Klasse nun zu verwenden, ist ganz einfach.
Zuerst binden wir die Klassen-Datei in unsere PHP-Datei ein, erzeugen ein neues Klassen-Objekt und speichern mit save() die gewünschten Werte zu einem selbst gewählten Schlüssel.

<?php 
require_once('path/memcache.class.php'); 
$mmc = new MMCache(); 
$key 'test_key'
$val 'This is out test value /7638263&&sect;$&/%&()=UIGCMJ).'
$mmc->save($key,$val); 
?>


Und genauso einfach, wie wir etwas gespeichert haben, können wir es nun auch wieder aus dem Speicher heraus holen:

<?php 
require_once('path/memcache.class.php'); 
$mmc = new MMCache(); 
$key 'test_key'
$result $mmc->load($key); 
?>


Das war es schon.
Als ergebnis von load() erhalten wir, wenn vorhanden, die Daten, die zuvor zu diesem Schlüssel gespeichert haben.
Sollte nichts im Speicher sein, erhalten wir ein FALSE zurück.

Memcache ist in meinen Augen eine der genialsten Weiterentwicklingen von PHP überhaupt.
Dadurch, dass sich der Load auf die Datenbank so rapide drosseln lässt, steigert es die Performance von großen PHP Applikationen enorm.
Aufpassen sollte man aber bei zu großen Datenmengen.
Zum Einen kann Memcache pro Key nur maximal 1 MB speichern und zum Anderen verlangsamt sich der Datenzugriff bei sehr großen Objekten stark.
Einfach mal ein bisschen in PHP rumtesten.

Und wer sich nun von mir davon überzeugen lassen hat, wie einfach das Caching mit dieser Klasse ist, der darf sie natürlich gerne nutzen :-)
Über eine eMail, wo sich meine Klasse befindet würde ich mich natürlich freuen.