Php - Cómo usar el cache  screenshot

Php - Cómo usar el cache

Te enseñamos cómo cacheamos en PHPNUKE

Utiliza Xcache en PHP para crear un sencillo y cómodo sistema de cache. Recuperar valores de base de datos generalmente es una función pesada y para lo cuál se suelen usar caches intermedios que evitan realizar conexiones siempre a la base de datos.

Para este tutorial te recomendamos que previamente estudies:

  • Acceso a base de datos
  • Funciones anónimas

En Php nuke utilizamos lo que hemos denominado 'caché en cascada', que consiste en ir consultando los caches más rápidos primero para ver si el dato que buscamos se encuentra ahí.

En caso de no encontrarse, vamos pasando a almacenamientos más pesados … hasta que por fin nos conectamos a la base de datos si no lo hemos encontrado antes.

Hemos creado una función llamada 'cache_get_callback' la cuál busca en el cache y en caso de no existir el dato lo genera.

<?php
$this->subdomain_row = cache_get_callback("employee_$id", function () use ($id) {
    $id = mysql_real_escape_string($id);
    $dbConnector = DbConnector::getInstance();
    $queryRes = $dbConnector->query("select * from employees where id=$id");
    return $dbConnector->fetch($queryRes);
});
?>

Esta función intentará recuperar la clave employee_$id de los diferentes cachés y en caso de no encontrarlo llamará a la función anónima que mostramos.

Si te fijas la función anónima no recibe argumentos, ya que como se va a invocar desde cache_get_callback y dicha función no quiere saber nada de argumentos, sólo quiere llamar a una función que genere el dato.

Por ello generamos la función anónima con el modificador 'use' … para que dicha función se genere con el dato del id internamente.

cache_get_callback

<?php
function cache_get_callback($name, $callback, $ttl = 7200) {
    $key = "call$name";
    $result = cache_get($key);
    if (empty($result)) {
        $result = array(
            "data" => $callback() ,
            "time" => time()
        );
        cache_set($key, $result, $ttl);
    }
    return $result["data"];
}
?>

Ya sólo queda generar las funciones cache_get cache_set que son las que leerán y escribirán en los diferentes caches que utilicemos.

cache_get y cache_set

<?php
function cache_get($cache_key) {
    if (isset($_GLOBALS[$cache_key])) {
        return $_GLOBALS[$cache_key];
    }
    if (xcache_isset($cache_key)) {
        return xcache_get($cache_key);
    }
    return false;
}
function cache_set($cache_key, $value, $ttl) {
    $_GLOBALS[$cache_key] = $value;
    xcache_set($cache_key, $value, $ttl);
    return false;
}
?>

Este caché en cascada graba en GLOBALS (para todo el REQUEST) y en xcache, pero puedes fácilmente configurarlo para que utilice otros almacenes de información.

La primera y más sencilla de las mejoras que puedes realizar es mantener el caché antiguo por más tiempo en caso de que la conexión a la base de datos esté fallando (o genere un timeout temporal).

cache_get_callback que gestiona errores de base de datos

<?php
function cache_get_callback($name, $callback) {
    $refresh_timeout = 60;
    $xcache_ttl = 7600;
    $key = "call$name";
    $result = cache_get($key);
    if (empty($result) || time() - $result[time] > $refresh_timeout) {
        $data = $callback();
        if (!$data) $data = $result[data];
        $result = array(
            "data" => $callback() ,
            "time" => time()
        );
        cache_set($key, $result, $xcache_ttl);
    }
    return $result["data"];
}
?>

Por último te vamos a mostrar como cacheamos múltiples elementos de una lista para solicitar a la base de datos sólo aquellos elementos que nos faltan en el caché, y solicitarlos todos a la vez.

<?php
class bookpublic static function get($ids) {
    if (is_numeric($ids)) {
        $result = self::get(array(
            $ids
        ));
        return isset($result[0]) ? $result[0] : false;
    }
    if (!is_array($ids)) return false;
    $result = array();
    $pending = array();
    foreach ($ids as $id) {
        $row = cache_get(books $id);
        if ($row) {
            $result[$id] = $row
        } else {
            $pending[] = intval($id);
        }
    }
    if (count($pending) > 0) {
        foreach (query(select * frombookswhereidin($pending_string)) as $row) {
            $id = $row[id]$pending_string = implode(“, ”, $pending);
            $result[$id] = $row;
            cache_set(books $id”, $row);
        }
    }
    return $result;
}
?>

Como ves, primero intentamos recuperar todos los libros del cache y vamos agregando a la lista $pending todos los que nos faltan. Después si algún libro no está en el caché lo solicitamos a la base de datos y finalmente retornamos los resultados.

Esta última función no utiliza cache_get_callback porque queremos recuperar todos los libros de una vez y no hacer muchas consultas a la base de datos aunque con un poco de ingenio podrás crear un cache_get_callback que te sirva para dichas tareas.

Estas técnicas son fácilmente transformables para que utilicen otros cache como couchbase, memcaché o apc.

¡Que tengas un feliz cache!