Ein kleiner PHP-Cache

Für große und kleine Optimierungen werden häufig Caches eingesetzt. Im Bereich Weban­wendungen meistens ein File-Cache. Beim ersten Aufruf einer Seite rattert der PHP-Code durch und die erzeugte HTML-Ausgabe wird als Datei gespeichert und ausgegeben. Bei jeder weiteren Anfrage wird dann nur noch auf die Datei zurückgegriffen. Der Gewinn besteht in geringerer Serverbelastung und schnellerer Ausgabe.

Bei meinen Unternehmungen die Datenbank­anfragen zu reduzieren, musste ich die Ergeb­nisse kurzzeitig zwischenspeichern. Ein File-Cache wäre simpler Overkill und ein Datenbank-Cache wäre, nun, dämlich in dem Fall.

Zum Einsatz kommt jetzt eine kleine Klasse, die einfach nur Werte in Variablen speichert und in jedem Scope erreichbar ist. Aufgrund der kurzen Lebensdauer, die nur die Länge einer Seiten-Anfrage hat, heißt die Klasse „RequestCache“.

Implementierung

class RequestCache {
  protected static $store = array();

  public static function save( $key, $value ) {
    self::$store[$key] = $value;
  }

  public static function key_exists( $key ) {
    return array_key_exists( $key, self::$store );
  }

  public static function load( $key ) {
    return self::$store[$key];
  }

  public static function delete( $key ) {
    unset( self::$store[$key] );
  }
}

Kleine Anmerkung: Ich arbeite mit einer statischen Klasse, genauso gut hätte man aber auch ein Singleton nehmen können. Bisher habe ich nichts Überzeugendes gefunden, was für das eine oder andere spräche.

Einsatz in freier Wildbahn

Der Titel einer Seite kann mehrfach benötigt werden: Für das title und die meta tags und natürlich als Überschrift selbst, vielleicht noch irgendwo anders auf der Seite. Das selbe Lied noch einmal mit der Beschreibung. Da ist es doch unsinnig, die Information immer wieder an­zufragen, wenn man sie nach dem ersten Mal doch schon in Händen gehalten hat?

function get_info( $show ) {
  switch( $show ) {

    case 'description':
      if( RequestCache::key_exists( 'description' ) ) {
        return RequestCache::load( 'description' );
      }
      $desc = mysql_fetch_object(
        mysql_query( 'SELECT p_desc, p_title FROM '
            . TABLE_POSTS . ' WHERE post_id = ' . P_ID )
      );
      RequestCache::save( 'title', $desc->p_title );
      RequestCache::save( 'description', $desc->p_desc );
      return $desc->p_desc;

    case 'title':
      if( RequestCache::key_exists( 'title' ) ) {
        return RequestCache::load( 'title' );
      }
      $title = mysql_fetch_object(
        mysql_query( 'SELECT p_desc, p_title FROM '
            . TABLE_POSTS . ' WHERE post_id = ' . P_ID )
      );
      RequestCache::save( 'title', $title->p_title );
      RequestCache::save( 'description', $title->p_desc );
      return $desc->p_title;

  }
}

Wird über die Funktion get_info() die Beschreibung oder der Titel zum ersten Mal abge­fragt, werden beide aus der Datenbank geholt und im Cache gespeichert. Wird ab sofort auch nur eines von beiden abgefragt, wird direkt aus dem Cache bedient und die DB-Anfrage ent­fällt. Von vielleicht 2~6 DB-Anfragen sind wir dann nur noch bei einer. Nett, oder?

Wann man ihn verwendet

Der RequestCache kommt in erster Linie zum Einsatz um Werte zu speichern, die in Funktionen ohne Klassenangehörigkeit verwendet und wahrscheinlich öfter benötigt werden. Auch denkbar ist der Austausch von Informationen zwischen Klassen, damit eine von beiden sich nicht selbst den Wert erst beschaffen muss (wozu sie allerdings die Funktionalität hat!).

Und wann nicht

Nicht verwendet werden sollte er, um ein Objekt in ein anderes hineinzutragen, das dort (als einzige Quelle) Informationen und/oder Funktionalität liefern soll. Stattdessen sollte man das Objekt über eine Methode der Klasse übergeben. Das Konzept wird als Dependency Injection bezeichnet. Ein guter Artikel hierzu: potstuck.com/2009/01/08/php-dependency-injection


Artikel zu Ende! *wirft eine Rauchbombe und verschwindet unter manischem Gelächter*