SPIP - Contrib

[ar] [en] [es] [fr] [it]



Accueil du site > Documentation > Tutoriaux pour le code de SPIP > Archives tutoriaux code SPIP > La genèse du nouveau compilateur

Cachez ce PHP que je ne saurais voir (mais montrez toutes mes tables)

Archive historique

mercredi 30 juin 2004, par Déesse A.. Dernier ajout samedi 23 juin 2007


Nouveaux systèmes de cache et de traduction des squelettes éliminant une passe de PHP.


Présentation

Les versions standards de Spip envoient aux navigateurs des pages HTML après une traduction en trois temps :

Squelettes Spip —> Script PHP/MySQL —> Script PHP —> HTML+JavaScript

Une réécriture complète du traducteur de squelettes et du système de cache (entrepris depuis 8 mois et décrit sur ce site) permet aujourd’hui d’éliminer la deuxième passe de PHP dans de nombreux cas, notamment le cas des squelettes de la distribution standard. Cette amélioration due au compilateur est prise en compte par le système de cache qui fonctionne alors comme un véritable cache de pages HTML, envoyées efficacement par le serveur Web comme s’il s’agissait de pages statiques, et non plus de scripts PHP nécessitant une nouvelle analyse syntaxique pour y trouver puis pour y évaluer les séquences "<?php ... ?>" insérées par le compilateur et/ou le squelette d’origine.

Méthode de compilation

La deuxième passe de PHP dans les versions actuelles de Spip a trois origines différentes :

- 1. la page HTML à produire varie selon le demandeur ;

- 2. le squelette utilisé inclut d’autres squelettes ;

- 3. le squelette utilisé contient du PHP.

Le point 1 concerne essentiellement les intervenants (administrateur, rédacteur, souscripteur de forum) authentifiés par un cookie. Le principe est de remplacer les séquences "<?php ... ?>" insérées par le compilateur standard, par l’appel d’une fonction JavaScript. Du coup, le code produit par le compilateur ne contient plus que du HTML et du JavaScript que l’on peut mettre en cache comme tel, et il suffit au script PHP principal (inc-public) de définir cette fonction à chaque connexion en l’insérant en début de page. En définitive, Spip délègue au navigateur une insertion de HTML beaucoup plus immédiate pour son interprète JavaScript que pour l’interprète PHP du serveur, trop sollicité de surcroît.

En ce qui concerne le point 2, rien en théorie ne motive de différer l’inclusion d’un squelette après l’exécution complète du squelette incluant, autrement dit d’appeler immédiatement une fonction d’inclusion au lieu de produire l’actuel "<?php include() ?>". En pratique, c’est délicat car le code PHP produit par le traducteur de squelettes doit être parfaitement réentrant, c’est-à-dire n’affecter aucune variable globale. Ce n’est doublement pas le cas du compilateur standard de Spip qui manipule une pile à l’aide de variables globales, et affecte à chaque entrée de fonction compilée les variables globales homonymes des index de la pile. Le compilateur proposé ici produit du code réentrant, compatible avec des inclusions à un niveau d’imbrication quelconque.

Le compilateur étant lui-même réentrant, on a expérimenté avec succès l’inclusion pendant la phase de compilation, lorsque la balise INCLUDE est sans paramètre (donc indépendante du contexte) et le squelette inclus sans PHP. Toutefois cette option n’a pas été retenue car elle grossit l’espace du cache pour un gain de temps imperceptible.

Un autre cas relevant de cette technique est le surlignement. La version actuelle diffère le surlignement après la mise en cache sans nécessité théorique, ce qui n’est pas le cas du compilateur ici proposé.

En ce qui concerne le point 3, le compilateur est alors obligé de revenir à la stratégie actuelle, la sémantique de Spip imposant l’exécution différée du PHP inséré dans un squelette. Toutefois, certains ajouts au compilateur devraient raréfier leur utilisation. Il s’agit notamment (certains points sont nouvaux, d’autres figurenet dans les articles et les forums consacrés aux versions successives du compilateur) :

- autorisation d’une balise SPIP dans les critères de boucle. Par exemple, le critère titre=#TITRE sert à trouver dans la base un autre objet ayant même titre que l’objet de la boucle englobante. Cette absence avait provoqué l’existence du critère "exclus" qui, avec cette innovation, peut s’exprimer tout simplement par "id_article !=#ID_ARTICLE".

- autorisation d’effectuer plusieurs comparaisons sur un même critère, par exemple {id_mot=16}{id_mot=2} (bug 168 jamais corrigé, voir la discussion ; ceci nécessite cependant MySQL 4.1).

- autorisation de paramètres comme 1,n-1 où n désigne le nombre d’éléments issus de la requête (voir les spécifications).

- tout champ des tables SQL est accessible par une balise SPIP homonyme en majuscule : cette référence est automatique suite à une réécriture de l’initialiseur de la BD qui permet au compilateur d’en connaître le contenu : les grosses variables rows_* du compilateur standard qui en étaient une copie partielle sont évacuées (c’est pourquoi le compilateur proposé n’est pas plus gros que l’actuel, bien qu’il offre plus de fonctionnalités). En revanche, existent deux tableaux permettant de débrayer cet automatisme : $exceptions_des_tables (si les noms des champs et/ou des tables SQL ne sont pas les homonymes SPIP) et $exceptions_des_champs (si l’on veut implanter un traitement ultra-spécifique dans l’aiguillage de inc-index-squel malgré l’homonymie).

Ce dernier point concerne non seulement les tables standards de Spip, mais aussi les tables accessibles par la connexion SQL, du moment que ces tables sont décrites par un tableau PHP dans le fichier ecrire/inc_auxbase.php3, et en déclarant global ce tableau dans le fichier ecrire/inc_globalbase.php3 : ces deux fichiers jouent un rôle équivalent à un include de .h en C. De la sorte, s’il existe une table nommée matable1 ayant des champs nom et adresse, on peut écrire dans un squelette :

<BOUCLE_1(matable1)><BR>#NOM #ADRESSE</BOUCLE_1>

et obtenir ce que les habitués de Spip devineront sans peine.

Méthode de cache

Pour profiter au maximum de cette amélioration du compilateur il est intéressant d’examiner avant la mise en cache si aucune interpolation de PHP ne figure dans la page produite, afin de l’envoyer tout de suite lors des prochaines consultations. Dans le cas d’un cache utilisant des fichiers, cela revient à sauver le résultat avec une extension .html ou .php selon le cas. Toutefois, la présente implémentation utilise un système de cache reposant sur le serveur SQL (voir ici pour une présentation et une discussion) qui a l’avantage d’invalider automatiquement les caches rendus caducs par l’apparition d’un nouvel article. Il est néanmoins envisageable d’écrire une autre version du fichier inc-cache (8 fonctions totalisant 6Ko seulement) qui utiliserait plutôt le système de fichiers (mais je rappelle que la version actuelle n’est pas totalement fiable faute de poser un verrou lors de la création de tels fichiers dans le répertoire CACHE).

Etats présent et futur

De toutes les balises SPIP nécessitant une authentification, seul FORMULAIRE_ADMIN a été réécrite sous forme d’un appel à une fonction JavaScript : cette stratégie est délicate à implémenter et on s’est donc limité pour cette première version à la balise la plus fréquente.

Les outils de mesures de performance sont d’une fiabilité médiocre, on y a donc renoncé. A l’usage (tant en local que sur un serveur distant ayant 350 visiteurs et 10 rédacteurs) ça semble effectivement plus rapide. Rappelons que ce nouveau compilateur a aussi la supériorité de restreindre les appels au serveur SQL aux seuls champs effectivement utilisés et de fournir un code PHP plus de 2 fois plus petit que les squelettes originaux.

Il est à noter qu’en cas de page 100% HTML, Spip peut à présent calculer le header Content-Length et générer un Connexion : close pour prévenir plus rapidement le client de la fin de l’envoi, quand bien même le processus Spip continue sa vie (pour indexation etc). Les expérimentations donnent toutefois des résultats contrastés selon les serveurs et proxies utilisés : la question doit donc être approfondie.

La présente modification d’une vingtaine de fichiers Spip est compatible avec la version 1.7 de Spip. Désolé pour ceux qui sont déjà passés à la 1.7.1 mais ce travail est loin d’avoir été immédiat. Si les développeurs de Spip veulent l’intégrer à la CVS, je veux bien faire la mise à jour nécessaire.

Pour l’installation, il faut détruire le fichier ecrire/inc_connect.php3 et procéder comme si on installait une nouvelle version de Spip : ceci aura pour effet de laisser intactes les tables déjà présentes, et de déclarer les tables de caches spécifiques. Signalons également que s’il existe dans $dossier_squelettes un fichier nommé mon-chercher.php3, celui sera lu à la place de inc-chercher.php3 afin d’y trouver la définition de la fonction chercher_squelette retournant le squelette associé au document demandé.

Bien que cette version tourne apparemment sans problème sur le site public mentionné, des bugs ne sont évidemment pas à exclure. Toute remarque et expérimentation sont donc les bienvenues. Une petite cerise sur le gateau : le formulaire de gestion des forums comporte un bouton supplémentaire permettant de répondre à un message en meme temps qu’on le valide ;

Documents joints


Répondre à cet article



Suivre la vie du site RSS 2.0 | Plan du site | Espace privé | Charte et vie SPIP-Contrib | SPIP | L'autre.net