PHP & MySQL

Les techniques de cache en PHP

Le 23 octobre 2007 à 20:32 par Séverin

A partir du moment où on veut optimiser la vitesse d’affichage de pages, réduire les ressources utilisées, limiter les accès base de données, il faut se tourner vers les techniques de cache.

En version simplifiée, le cache est une version mémorisée du résultat d’une action qu’on utilise plutôt que de refaire cette action à chaque fois. On économise ainsi les ressources et le temps de l’action.

Par exemple, sur un digg-like, le code HTML de la page des dernières news peut être mémorisé dans un fichier. Ce fichier n’est recréé que quand une nouvelle news est ajoutée. Entre temps, les utilisateurs reçoivent donc instantanément le code HTML sans avoir à passer par la base de donnée.

Comme dans cet exemple, on peut stocker le code HTML afin de le renvoyer directement, mais on peut aussi cacher des données, par exemple le résultat de requêtes SQL.

Cache HTML

Ne vous inquiétez pas, il ne va pas falloir réécrire tout votre site pour remplacer les echo par l’écriture d’une chaîne de Caractères. Depuis PHP 4, une série de fonctions permet d’intercepter les echo dans un buffer, les fonction ob_xxx(). Petit exemple :

  1. echo ‘Avant le buffer’;
  2.  
  3. // On démarre l’interception
  4.  
  5. echo ‘Dans le buffer’;
  6.  
  7. // On récupère le contenu du buffer
  8. buffer = ob_get_contents();
  9. // On arrête l’interception et on affiche le buffer
  10.  
  11. echo ‘Après le buffer’;
  12.  
  13. echo ‘Le buffer contient : ‘.$buffer.‘;

Affiche : Avant le buffer Dans le buffer Après le buffer Le buffer contient : Dans le buffer ob_start commande le début de l’interception des echo. ob_get_contents récupère le contenu du buffer créé ob_end_flush arrête l’interception des echo et affiche le contenu du buffer D’autres fonctions permettent de gérer plus finement la façon dont un intercepte les echo et quand on affiche, vide ou lit le buffer. Avec l’ensembles de ces fonctions, on peut facilement intercepté le code qui nous intéresse pour ensuite le stocker dans un fichier. Voilà deux fonctions qui permettront par exemple de ne régénérer une zone de code qu’au bout d’un temps donné :

  1. function debutCache($fichier, $secondes){
  2.  
  3.     // Si le cache n’existe pas ou si le temps est dépassé.
  4.     if(!file_exists($fichier) ||
  5.                time()>filemtime($fichier)+$secondes){
  6.  
  7.         // On démarre l’interception
  8.         ob_start();
  9.  
  10.         return true;
  11.  
  12.     }else{    // Si le cache est toujours valide
  13.  
  14.         // On affiche le contenu du cache
  15.         echo file_get_contents($fichier);
  16.  
  17.         return false;
  18.     }
  19. }
  20.  
  21. function finCache($fichier){
  22.  
  23.     // On récupère le résultat de l’interception
  24.     $buffer = ob_get_contents();
  25.  
  26.     // On arrête l’interception et on affiche le code
  27.     ob_end_flush();
  28.  
  29.     if($buffer){    // Si on a un buffer
  30.  
  31.         // On l’enregistre
  32.         $file = fopen($fichier, ‘w’);
  33.         fwrite($file, $buffer);
  34.         fclose($file);
  35.     }
  36. }
  1. // On cache le contenu du code à suivre et on le met à jour que si le cache est plus vieux que 60 secondes.
  2. if(debutCache(‘cache.html’, 10)){
  3.     …
  4.     … // Votre code PHP
  5.     …
  6.  
  7.     finCache(‘cache.html’);
  8. }

Cache de données

A nouveau, pas besoin de tout réécrire. Ce coup-ci ce sont les fonctions serialize() et unserialize() qui vont être mises à contribution. Serialize sert à transformer n’importe quelle donnée en chaîne de caractère. Ca marche également pour les objets et les tableaux. Unserialize retransforme ces chaînes dans leur format d’origine. Petit exemple :

  1. $tableau = array(‘nom’=>‘Dupont’,
  2.                  ‘prénom’=>‘Jean’,
  3.                  ‘téléphone’=>array(123456, 7891011));// On transforme le tableau en chaîne de caractères
  4. $serialize = serialize($tableau);
  5.  
  6. // On supprime complètement le tableau
  7. unset($tableau);
  8.  
  9. // On récupère le tableau depuis la chaîne de caractères
  10. $tableau = unserialize($serialize);
  11.  
  12. print_r($tableau);

Affiche : Array ( [nom] => Dupont [prénom] => Jean [téléphone] => Array ( [0] => 123456 [1] => 7891011 ) ) Et si on utilise la fonction eval, qui sert à exécuter une chaîne de caractère en PHP, on peut mettre en cache le résultat d’une fonction avec la fonction suivante :

  1. function cacheDonnées($fichier, $function, $secondes){
  2.  
  3.     // Si le cache n’existe pas ou si le temps est dépassé.
  4.     if(!file_exists($fichier) ||
  5.                time()>filemtime($fichier)+$secondes){
  6.  
  7.         // On récupère le résultat de la fonction
  8.         $données = eval(‘return ‘.$function.‘;’);
  9.  
  10.         // On transforme en chaîne de caractères
  11.         $cache = serialize($données);
  12.  
  13.         // On l’enregistre
  14.         $file = fopen($fichier, ‘w’);
  15.         fwrite($file, $cache);
  16.         fclose($file);
  17.  
  18.         return $données;
  19.  
  20.     }else{    // Si le cache est toujours valide
  21.  
  22.         // On récupère la chaîne de caractère mise en cache.
  23.         $données = file_get_contents($fichier);
  24.  
  25.         // On retransforme les données dans leur format d’origine.
  26.         $données = unserialize($données);
  27.  
  28.         return $données;
  29.     }
  30. }
  1. function test(){
  2.     return array(’secondes’=> time(),
  3.                  ‘nom’=>‘Dupont’,
  4.                  ‘prénom’=>‘Jean’,
  5.                  ‘téléphone’=>array(123456, 7891011));
  6. }
  7.  
  8. $tableau = cacheDonnées(‘cache.html’, ‘test’, 10);
  9.  
  10. echo $tableau[’secondes’];

Petite parenthèse pour signaler que la commande eval est potentiellement extrêmement dangereuse. Si elle utilise des paramètres de l’URL, elle peut permet à une personne malveillante d’exécuter du code PHP sur votre serveur si vous n’avez pas pris les précautions nécessaires. Pensez donc bien à cette possibilité avant d’utiliser eval.

5 commentaires »

Gravatar

Commentaire de Grummfy

le 24 octobre 2007 à 17:08

Hello,
petite remarque, serialize est pas super point de vue performance ….

a noté, que dans le cas où vous écrivez peux souvent le cache, une solution est peut-être de sauver sous forme d’un tableau dans un fichier .php directement …

Gravatar

Commentaire de Olivier

le 25 octobre 2007 à 18:32

Bon billet, toutefois, quelques remarques.
Concernant le cache données, la sérialisation n’est pas à proprement parler du cache. Cette dernière sert par exemple à sauvegarder (en base, en fichier, en mémoire) l’état d’un objet à l’instant T afin de le retrouver intact lors d’une prochaine utilisation, ou pour envoyer par services web (sérialisation JSON, …). L’utilisation typique est par exemple : sauvegarde de critères de recherche, l’objet est sérialisé (avec les valeurs lors de la sélection), ce qui permet de retrouver les valeurs plus facilement. Comme le souligne Grummfy, la sérialisation ça reste consommatrice en ressources.

Pour le cache, j’aurais plutôt cité Memcached (http://fr.php.net/memcache) qui est beaucoup plus efficace AMHA.

Gravatar

Commentaire de Séverin

le 25 octobre 2007 à 22:57

En effet, la sérialisation n’est pas du cache, ce qui est du cache c’est de stocker les données. La sérialisation est une des façon possibles. On peut aussi générer un code PHP qui réécrirait l’objet ou le tableau.

Sinon, je connaissais pas memCache. Je vais lorgner un peu de ce coté, ça à l’air pas mal du tout.

Gravatar

Trackback de pligg.com

le 31 octobre 2007 à 1:20

Techniques de cache en PHP…

Toujours sur SmashingCoding, les techniques de caches abordes en PHP….

Gravatar

Pingback de Tecniche di cache con php : sastgroup.com

le 9 avril 2008 à 14:50

[…] web: http://smashingcoding.com/2007/10/23/les-techniques-de-cache-en-php/ Share and Enjoy: These icons link to social bookmarking sites where readers can share and […]

Laisser un commentaire

Votre Nom

Votre E-mail (obligatoire mais ne sera pas publié)

Votre Site ou blog

Votre commentaire

Valid XHTML 1.0 Transitional