[POO]SYSTÈME DE CACHE

neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 - 7 déc. 2009 à 17:06
destinyfr Messages postés 106 Date d'inscription samedi 19 mai 2007 Statut Membre Dernière intervention 13 avril 2009 - 28 déc. 2009 à 12:44
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/50940-poo-systeme-de-cache

destinyfr Messages postés 106 Date d'inscription samedi 19 mai 2007 Statut Membre Dernière intervention 13 avril 2009
28 déc. 2009 à 12:44
Mise à jour du code, refonte complète. J'attends vos commentaires :)
destinyfr Messages postés 106 Date d'inscription samedi 19 mai 2007 Statut Membre Dernière intervention 13 avril 2009
8 déc. 2009 à 20:38
Salut,

Merci pour ton retour :) je suis preneur sur tout :p c'est via d'autres avis que l'on s'améliore de toute façon. Je ne vais pas trop m'étendre sur le sujet pour le moment car les cours me prennent pas mal de temps. Je vais prendre en comptes tes commentaires et améliorer la classe. J'ai déjà commencé mais il m'en reste à faire.

Merci pour tes commentaires, si tu veux rajouter des choses etc.. n'hésite pas ! Je suis au contraire pour :)

Dès que j'ai mis à jour, j'envoie.
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
8 déc. 2009 à 00:56
Plop,

Merci pour ta réponse.
Je préfère être clair : je ne dénigre pas ta source, je ne fais que lui confronter mes arguments. Je ne prétends pas détenir la vérité, j'énonce simplement ce que je pense, ma manière de voir les choses et je cherche à partager des interrogations. Si tu te poses les questions que je me pose, alors la plus grosse partie des objectifs de mes commentaires est atteinte.

J'entends tes arguments concernant les différents templates et la multiplication des fichiers comme des petits pains. Héhé, bien entendu, j'ai encore des arguments à y confronter ;)

Concernant les templates multiples, je suis persuadé que dans 90% des cas, on peut modifier le template avec uniquement un nouveau CSS. Je ne peux pas apporter de démonstration, mais c'est une conviction que j'ai.

Concernant la multiplication des fichiers de cache : ce n'est en réalité pas un problème. Les fichiers de cache sont gérés par le système de cache, pas par le développeur. Tant que le système de cache sait quel fichier correspond à quoi et qu'il fournit les outils permettant de manipuler facilement et efficacement les fichiers mis en cache, alors s'il y a 30 fichiers différents pour la même page mais avec différents templates, ou s'il faut 50 fichiers à assembler pour composer la page d'accueil, peu importe : le système de cache sait quoi assembler et comment. L'utilisateur n'a pas à mettre le nez dedans, c'est pas son problème. C'est un peu comme si tu cherchais à savoir si ton OS n'utilise pas trop de registres dans la RAM pour fonctionner : c'est pas ton problème, tant qu'il les gère correctement.

Les deux problmatiques sont liées : rien n'empêche de composer une page avec plusieurs fichiers de cache et une partie dynamique, et ce plusieurs fois pour plusieurs templates.
Ainsi, si tu as 15 templates et qu'il faut générer 15 fichiers de cache juste pour les news pour chaque template, je ne vois pas où est le problème : le système de cache doit permettre ça.
Et si tu veux hiérarchiser tes fichiers de cache, pour y voir plus clair quand tu développes ton site, c'est pas un problème non plus : le système de cache est censé être capable de gérer les fichiers quel que soit leur emplacement (chemin/répertoire).
Le cache HTML de la liste de news sera donc généré pour chaque template chaque fois qu'un utilisateur utilisant ce template affiche la page d'accueil, si le fichier de cache n'existe pas déjà.
Ou alors, lorsque tu postes un nouvel article, ton back office va générer les fichiers de cache pour tous les templates, une bonne fois pour toute (puisque de toute façon, la requête ne sera exécutée qu'une seule fois, il n'y a que le template qui est parsé avec des valeurs qui ne changent pas). A ce moment là, pour la génération du cache, peu importe si ça prend 10 secondes : c'est du back office, qui n'est vu que par un seul utilisateur à un instant T. On ne pourrait pas admettre qu'il faille 10 secondes pour poster un message sur un forum, mais un article dans l'admin... les utilisateurs ne sont pas impactés, donc ça peut bien prendre le temps qu'il faut.

Voilà voilà, je vais aller dormir maintenant, parce que quand même...
destinyfr Messages postés 106 Date d'inscription samedi 19 mai 2007 Statut Membre Dernière intervention 13 avril 2009
7 déc. 2009 à 23:55
Salut,

Comme tu l'as très bien dit, le cache est mis à jour lorsqu'un nouvel article (ou bien topic sur un forum, un commentaire etc.. bref ce que tu veux) est posté (d'où l'inutilité de vérifier la validité du fichier cache car il sera régénéré).
Je préfère mettre en cache un retour de requête plutôt que du html car dans mes codes, je dispose de plusieurs templates. Il est vrai que j'aurai pu mettre en cache le html (et pour vérifier que le cache soit à jour après un nouvel article, vider celui-ci, ce qui aurait obligé un rechargement du cache sur l'index => ce n'est qu'une façon comme une autre !) mais cela m'aurait obligé à créer un fichier cache par template (je parle pour une page index avec des news uniquement).
Or via cette méthode de cache, je peux avoir un fichier cache global, c'est à dire le même quelque soit le template utilisé.
Je pense surtout que c'est la raison principal pour laquelle je stock un retour requête.

Ce type de cache peut (je pense) être utile lorsqu'il y à différentes requêtes sur une page et dont les mises à jours varient. Je vais prendre l'exemple d'un compteur de visite sur une page de news. Le compteur de visite à pour obligation d'enregistrer 1 seul et unique fois un visiteur ayant la même IP, les news elles sont mises à jour que lors qu'il y à un nouvel article d'ajouté sur le site.

Comme tu auras surement compris, le compteur de visite sera mis à jour bien plus souvent que les news. Le fait de stocker des requêtes dans des fichiers et non tout le code html dans 1 fichier, permet de mettre à jour une seul partie du cache.
En admettant qu'il n'y est aucun nouvel article de la journée, inutile de mettre à jour les news. Par contre, si plusieurs utilisateurs arrivent sur le site, le compteur de visite devra lui être à jour. Donc qu'est-ce qu'il ce passe ? Il y à deux possibilités :
Soit les visiteurs sont déjà passés, on leur affichent donc le contenu du cache (donc chargement du retour de requête).
Soit un visiteur dans le total de visiteur est nouveau, on va donc mettre à jour le nombre dans la base de donnée et recharger le cache du compteur de visite uniquement ! (les prochains arrivant sur le site verront le nouveau nombre si ils sont déjà passés, sinon retour à l'étape précédente. Les visiteurs ayant déjà chargés la page (avant mise à jour dans la BDD et du cache) auront l'ancien nombre et ne verront que le nouveau sur rafraichissement de la page).

Ici, si j'avais stocké tout le code html de la page, j'aurai été obligé de recharger toute la page et non une partie uniquement. (il doit bien y avoir la possibilité de faire la même chose même si on stock le code html de la page, mais je reste dans du simple ici).

Un avantage serait une mise à jour partielle du cache. Côté inconvénients, ça oblige à avoir plus de fichiers pour 1 page (quoi que le cache du compteur de visite peut-être réutilisé pour plusieurs pages) et il est possible qu'il y est un ralentissement de la page.

Côté performances entre ce type de cache et un cache html, je n'ai pas comparé les deux donc je ne dis pas que l'un est meilleur que l'autre (et au pire je ne suis pas la pour juger la dessus, même si les performances sont quelque chose de très important).

Voilà j'ai tenté de t'expliquer un peu mieux l'utilité d'un cache comme celui-ci. Il est fort probable que tout soit fesable en stockant du html plutôt qu'un retour de requête. Je tiens encore une fois à préciser que cette façon n'est en aucun cas la meilleur et que j'approuve ta vision concernant les caches, je comprends tout à fait qu'il soit plus logique de mettre du code html dans le fichier directement.

Est-ce que cela te convient ou tu souhaites savoir plus de choses sur d'autres points ?

Merci encore pour tes commentaires :)
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
7 déc. 2009 à 22:31
Plop,

Je crois que je vois à peu près pourquoi t'as pas de gestion du temps : le cache est mis à jour quand tu postes un nouvel article, c'est ça ? Dans ce cas, pas besoin de le regénérer à intervalles réguliers.
Du coup, je ne comprends pas pourquoi tu choisis de mettre un résultat de requête plutôt que du html... Dans ce cas précis, ce n'est pas pertinent : autant avoir du html pré-digéré prêt à afficher plutôt que des données qu'il faudra de toute façon traiter, toujours de la même façon... Il me paraît préférable de traîter les données une bonne fois pour toute.
Je ne dis pas par là que ton cache est inutile, juste que dans le contexte que j'imagine (une liste d'articles sur une page d'accueil par exemple), ce n'est pas justifié de faire un tel cache plutôt que de mettre en cache du html.
Tu as peut-être des arguments en faveur de ton implémentation, je suis curieux de les avoir pour confronter nos points de vue (de manière constructive, hein, donc).
destinyfr Messages postés 106 Date d'inscription samedi 19 mai 2007 Statut Membre Dernière intervention 13 avril 2009
7 déc. 2009 à 22:23
Salut,

Merci pour le commentaire ^^
Il est vrai que le cache est simple (en même temps j'ai pas dit que c'était le meilleur cache du monde :D). Pour ce qui est de la vérification sur le temps des fichiers, je n'en voyais pas l'utilité car ma conception d'un cache est un peut différente. Pour le problème entre la fonction read et __get, c'est très largement améliorable, en effet et j'aurais du y penser bien avant (gros erreur de ma part). Pour la méthode delete, j'y avais pensé, et elle était présente (au départ), mais ayant une conception de ce qu'est un cache, je n'en voyais pas ici l'utilité (car étant donnée que si aucun article est mis à jour, le cache n'as pas forcément besoin de changer).

Bref c'est une version basique et très peu complète d'un cache, c'est vrai. Je le modifie dès que possible (surement à partir de demain soir) et je posterai un mise à jour dès que possible.

Pour ce qui est de l'array, c'est du faite de l'utilisation de fetchAll. Je vais remédier par la même occasion à ce problème.

Merci encore pour ton commentaire, je vais prendre en compte ce que tu viens de dire et modifier tout ça.

Merci !
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
7 déc. 2009 à 17:06
Salut,

Ce que tu mets en cache, ce n'est pas un objet, mais un tableau. Et un tableau n'est pas un objet, en php : c'est un tableau.

Pour que les fonctionnalités soient toutes présentes, il manque une fonction delete().

Ta méthodes read() n'intéragit pas correctement avec la méthode __get() : elle ne devrait pas retourner le contenu du fichier, mais plutôt un booléen en cas de succès. Le contenu du fichier devrait alors être automatiquement stocké dans une propriété pour être réutilisé plus tard par __get(). Tel que ça fonctionne actuellement, si le fichier existe et n'est pas accessible en lecture, tu te retrouves avec une erreur.
La méthode __get() n'est pas vraiment optimisée... Tu exécutes 2 fois unserialize() sur une variable dont tu ignores la taille. Par ailleurs, aucune vérification si ce n'est la nature du résultat (array ou non)
Pour bien faire, il faudrait donc que :
- la méthode read() vérifie, avant de le lire, que le fichier existe ET EST ACCESSIBLE EN LECTURE (parce que ça peut ne pas être le cas, et si le fichier ne peut pas être lu, tu te retrouves avec une erreur => autant anticiper)
- la méthode read() stocke le contenu du fichier dans une propriété et renvoie TRUE en cas de succès, FALSE sinon
- la méthode __get() retourne TOUJOURS quelque chose SANS ERREUR. Si le contenu du fichier est utilisable, alors elle le renvoit délinéarisé. Sinon, il faut qu'elle renvoit autre chose. En l'état actuel, elle repose sur le postulat que la méthode read() renverra TOUJOURS un résultat exploitable... Ce qui peut s'avérer faux et causer... un bug.

Enfin, ton exemple est un mauvais exemple. Il illustre certes le fonctionnement de la classe et ses méthodes, mais il est déplorable en terme de performances.
Tu utilises PDO, c'est très louable. Rien que pour ça, je te remercie du fond du coeur. Mais utiliser fetAll(), écrire le résultat SYSTÉMATIQUEMENT dans un fichier puis itérer dessus n'a pas de sens. Par ailleurs, préparer une requête dans laquelle il n'y a aucun paramètre est une perte de performances : autant utiliser PDO::query() directement.
La classe PDOStatement implémente l'interface Traversable ce qui la rend utilisable directement dans une boucle foreach(). L'utilité d'un itérateur est, rappelons-le, de ne parcourir un objet qu'une seule fois.

Enfin, il manque la gestion du temps : un cache sans durée de vie n'a pas de sens. Il est indispensable de savoir quand le fichier de cache doit être régénéré. Il ne doit pas l'être systématiquement (sinon il ne sert à rien), mais il doit quand même l'être de temps en temps (à déterminer par l'utilisateur, pour chaque fichier ou pour toutes les instances, ça, c'est toi qui voies) sinon les données seront obsolètes...
Ton exemple devrait donc montrer comment vérifier si les données sont présentes en cache, comment utiliser le cache s'il existe pour un résultat donné, comment le réécrire s'il n'existe pas ou s'il est obsolète, etc.
Il faut aussi penser à un système de purge, type garbage collector, pour supprimer les fichiers de caches périmés (de manière plus ou moins automatique, mais une méthode spécifique devrait permettre ça facilement).

Un défaut de ton système est que le nom du fichier est déterminé d'après le md5 du contenu : cela signifie qu'il faut obligatoirement exécuter la requête pour ensuite vérifier si le résultat est en cache ou non. Or tout l'intérêt d'un fichier cache est de NE PAS avoir à exécuter la requête si son résultat existe déjà... Il est donc préférable de laisser l'utilisateur choisir le nom de son cache (il est grand quand même, il est censé savoir développer en PHP et gérer correctement ses variables) et lui faire confiance (ou pas : d'où la nécessité de toutes les vérifications que tu omets).

Voilà voilà... ^^
Rejoignez-nous