OVH Cloud OVH Cloud

de l'utilite des templates (long)

13 réponses
Avatar
Gabriel
bonjour,

tout d'abord, ceci n'est pas un troll :)

Voici la question que je me poste depuis un certain temps :
J'utilise pour mes développements php un modèle mvc avec une page
index.php qui appelle telle ou telle fonction en fonction de la valeur
du paramètre action :
index.php?action=login -> appelle une fonction qui charge le template
login.tpl contenant ceci :
{err_login}
input value="{login}
input value="" name="pwd" bla bla...
Supprime tout ce qui se trouve entre accolades et echo la variable.

et en cas d'erreur lors de l'identification, :
je charge le template dans une variable
je remplace les err par le msg qui va bien
je remets le login entré
je fais echo $template et c'est reparti :)

A la lumière de certains posts du groupe (php EST un moteur de template
lui-même), j'en suis venu à m'interroger s'il ne serait pas plus
judicieux de creer un tableau ou objet (je suis pas sectaire :)) en
session et de faire une redirection (via un header:location) vers la
page login.php.

Cette page login php contiendrait le formulaire de login qui était
auparavant dans le template et testerait la présence et les valeurs du
tableau et au lieu d'avoir des {err_login}, j'aurai des :
<? echo $informations['login'] ?> où information est le fameux tableau
stocké en session.
J'incluerai évidemment dans chaque page un quelconque système de
contrôle pour vérifier qu'une personne n'a pas appelé la page
directement, sans passer par le controlleur.

Les questions sont les suivantes :

Est-ce que faire 20 <? echo $toto;?> est plus coûteux que charger le
template et faire des str_replace et un seul echo à la fin du traitement
(non ce n'est pas de la s.... de mouche, je voudrais connaitre vos
retours d'expérience en fait car mes lectures m'ont dit que
l'instruction de pré-processing qui lance l'interpréteur php est
coûteuse à force (PHP 5 Campus presse) ?

Les moteurs de templates semblent être à la mode en php :); mais je
m'interroge car des include fonctionnent aussi très bien (j'ai dit pas
de troll, je pose la question simplement ;))

Le but final étant de développer une implémentation de modèle MVC qui
jusqu'à présent se basait sur des templates et qu'aujourd'hui, je tente
de refondre et optimiser...

Merci d'avoir lu jusque là :)

take off my hat.

10 réponses

1 2
Avatar
John GALLET
Bonjour,

tout d'abord, ceci n'est pas un troll :)
Ca n'en a pas l'air du tout, les questions que tu poses sont tout à fait

légitimes. Gênantes parce qu'on peut ensuite se demander pourquoi on élève
au pinnacle des trucs qui semblent réinventer la roue octogonale, mais
tout à fait légitimes.

session et de faire une redirection (via un header:location) vers la
page login.php.
Déjà : non. Si tu commences par faire faire un ping pong inutile et par

filtrer tes variables DEUX fois au lieu d'une (parce qu'en bon
développeur, tu filtres toutes les variables en entrée, n'est-ce pas ?) tu
as déjà perdu 10 fois le peu que tu vas gagner en changeant de méthode
d'implémentation de séparation logique-présentation.
Donc ***pas*** header(location toto.php?arg1=...&arg2=...) pour deux
raisons :
1) http://faqfclphp.free.fr/#rub2.11
2) s'il s'agit de données confidentielles, elles serotn stockées en clair
dans le log http (car en get) et c'est jamais bon.

J'incluerai évidemment dans chaque page un quelconque système de
contrôle pour vérifier qu'une personne n'a pas appelé la page
directement, sans passer par le controlleur.
Si tu fais directement

require('sous_repertoire_interdit/login.php');
exit();
à la place de ton header(location, il est vite trouvé, le système...
On en a parlé ici même il n'y a pas si longtemps que ça, deux solutions
cumulables :
- .htaccess avec <DENY FROM ALL> dans le sous répertoire
- et/ou dans section de vérification define('MABELLECONSTANTE') et dans
les fichiers "privés" if(!defined('MABELLECONSTANTE')) exit(); en première
ligne.

Est-ce que faire 20 <? echo $toto;?> est plus coûteux que charger le
template et faire des str_replace et un seul echo à la fin du traitement


Tu montes en mémoire la même quantité de données. Dans le premier cas
c'est le moteur de php, qui est quand même écrit pour, qui fait le
parsing. Dans le second, il faut quand même lire le fichier, puis faire le
même nombre de str_replace sur TOUT le texte si c'est mal foutu, sur des
zones plus précises si le moteur de template l'accepte.

Seule réponse donc : faire un bench. Armel en avait fait un très bien sur
www.phpindex.com : http://www.phpindex.com/download/templates2.php3
mais il date un peu. En revanche le score est sans appel à l'époque :
- FastTemplate : 40% de perfs de php seul.
- phplib : 80 à 90 %.
- vtemplate : 60 à 70%

En revanche, dès lors que le moteur de templates embarque un cache,
évidemment, ça améliore sacrément les perfs, mais c'est un autre mécanisme
qui n'a rien à voir.

Les moteurs de templates semblent être à la mode en php :)
Ca fait un certain nombre d'années oui, le bench de phpindex date de

février... 2002.

m'interroge car des include fonctionnent aussi très bien
oui. D'ailleus il faudrait plutôt require() au delà de php3...


Le but final étant de développer une implémentation de modèle MVC qui
jusqu'à présent se basait sur des templates et qu'aujourd'hui, je tente
de refondre et optimiser...
Qui se basait sur un *moteur* de template. Tu as encore des templates si

tu remplaces {LOGIN} par <?php echo $login;?> il n'y a vraiment que la
**syntaxe** du placeholder qui change dans le fichier template, et
l'impossibilité de faire des boucles avec un seul fichier.

a++;
JG

Avatar
gabriel
bonsoir,

Ca n'en a pas l'air du tout, les questions que tu poses sont tout à fait
légitimes. Gênantes parce qu'on peut ensuite se demander pourquoi on élève
au pinnacle des trucs qui semblent réinventer la roue octogonale, mais
tout à fait légitimes.
juste, c'est tout l'objet de ma réflexion :) : prq refaire le travail de

php ??

session et de faire une redirection (via un header:location) vers la
page login.php.


Déjà : non. Si tu commences par faire faire un ping pong inutile et par
filtrer tes variables DEUX fois au lieu d'une (parce qu'en bon
développeur, tu filtres toutes les variables en entrée, n'est-ce pas ?)
Tout à fait, je le mets avant toute autre action.

tu > as déjà perdu 10 fois le peu que tu vas gagner en changeant de méthode
d'implémentation de séparation logique-présentation.
Donc ***pas*** header(location toto.php?arg1=...&arg2=...) pour deux
raisons :
1) http://faqfclphp.free.fr/#rub2.11
2) s'il s'agit de données confidentielles, elles serotn stockées en clair
dans le log http (car en get) et c'est jamais bon.
Hmm, en fait je me suis mal exprimé : les données à utiliser dans la page sont contenues dans la session :
je me rapproche en fait d'une architecture à la java avec des javabeans

dans
l'objet session mis à la dispositio de la jsp (la vue donc) qui les
exploite en fonction du besoin -> la page ne controle donc pas les
données puisque c'est le controleur qui a délégué le travail au modèle.

J'incluerai évidemment dans chaque page un quelconque système de
contrôle pour vérifier qu'une personne n'a pas appelé la page
directement, sans passer par le controlleur.


Si tu fais directement
require('sous_repertoire_interdit/login.php');
exit();
à la place de ton header(location, il est vite trouvé, le système...
On en a parlé ici même il n'y a pas si longtemps que ça, deux solutions
cumulables :
- .htaccess avec <DENY FROM ALL> dans le sous répertoire
- et/ou dans section de vérification define('MABELLECONSTANTE') et dans
les fichiers "privés" if(!defined('MABELLECONSTANTE')) exit(); en première
ligne.
Oui voilà, la deuxième est effectivement ce que j'avais en tête...

Est-ce que faire 20 <? echo $toto;?> est plus coûteux que charger le
template et faire des str_replace et un seul echo à la fin du traitement



Tu montes en mémoire la même quantité de données. Dans le premier cas
c'est le moteur de php, qui est quand même écrit pour, qui fait le
parsing. Dans le second, il faut quand même lire le fichier, puis faire le
même nombre de str_replace sur TOUT le texte si c'est mal foutu, sur des
zones plus précises si le moteur de template l'accepte.
Je pensais que que les <? echo ... avaient un coût non négligeable : il

semble donc que j'avais tort...

Seule réponse donc : faire un bench. Armel en avait fait un très bien sur
www.phpindex.com : http://www.phpindex.com/download/templates2.php3
mais il date un peu. En revanche le score est sans appel à l'époque :
- FastTemplate : 40% de perfs de php seul.
- phplib : 80 à 90 %.
- vtemplate : 60 à 70%

En revanche, dès lors que le moteur de templates embarque un cache,
évidemment, ça améliore sacrément les perfs, mais c'est un autre mécanisme
qui n'a rien à voir.
Evidemment.


[snip]

oui. D'ailleus il faudrait plutôt require() au delà de php3...
Je dirais même plus require_once, non ?

Le but final étant de développer une implémentation de modèle MVC qui
jusqu'à présent se basait sur des templates et qu'aujourd'hui, je tente
de refondre et optimiser...


Qui se basait sur un *moteur* de template. Tu as encore des templates si
tu remplaces {LOGIN} par <?php echo $login;?> il n'y a vraiment que la
**syntaxe** du placeholder qui change dans le fichier template, et

C'est vrai que ca reste un système de templates mais mnt c'est php qui

effectue le chargement et le parsing du fichier au lieu que cela soie
à la charge du développeur.

Sinon, dans l'idée c'est identique.
l'impossibilité de faire des boucles avec un seul fichier.
Oui là, par-contre, il va falloir que je trouve quelque chose....

Ok, merci pour tout john en tout cas et bonne soirée.

Cordialement,


Avatar
dmetzler
La question est effectivement pertinente. Un article expliquait très
bien comment se passer de moteur de template en utilisant PHP. La
plupart des moteurs de template font du str_replace ou des mécanismes
un peu plus évolués mais similaire.

Dans mon cas j'utilise Smarty qui est un bon compromis entre moteur de
template totalement dynamique (ie le template est réévalué à chaque
fois) et php. Smarty, lorsqu'il voit une template pour la première
fois la compile et génère rien de moins qu'un fichier PHP de manière
transparente.
On bénéficie ainsi de la séparation Code/Présentation tout en
gardant un code efficace. Smarty permet aussi de cacher certaines
parties des pages et donc d'accélérer encore le traitement.
Avatar
John GALLET
Re,

juste, c'est tout l'objet de ma réflexion :) : prq refaire le travail de
php ??


Cela avait un avantage non négligeable à l'époque où beaucoup d'éditeurs
ne comprenaient pas les balises php et **pourrissaient** le code dès
l'ouverture du fichier. Pour un infographiste ou autre, il est possible
avec une solution de template de ne strictement rien connaître au codage.
Enfin, en théorie.

Hmm, en fait je me suis mal exprimé : les données à utiliser dans la
page sont contenues dans la session :
Alors tu auras seulement gagné le non ping-pong des données, mais tu fais


quand même un aller-retour pour des prunes. Je rappelle que header( )
envoie des données au NAVIGATEUR pour qu'il REDEMANDE une autre age, ce
qui dans 99% des utilisations actuelles est DEBILE.

l'objet session mis à la dispositio de la jsp (la vue donc) qui les
exploite en fonction du besoin -> la page ne controle donc pas les
données puisque c'est le controleur qui a délégué le travail au modèle.
Ok pour cette partie là, mais ce qui prend le plus de temps, c'est pas la

validation, c'est la latence réseau.

Je pensais que que les <? echo ... avaient un coût non négligeable : il
semble donc que j'avais tort...


Je n'ai pas dit ça. Je en suis pas capable de dire(1) quel est le coût
exact du parsing et de l'entrée en scripting, puis sortie du moteur etc...
La seule chose que j'en dis c'est que la quantité de données à mouliner
est la même, et que les manipulations de chaînes de caractères surtout à
coups de regexp si elles sont utilisées sont toujours coûteuses.

(1) i.e. je n'ai jamais fait de benchs à ce sujet, mais ça doit bien
traîner qq part

oui. D'ailleus il faudrait plutôt require() au delà de php3...
Je dirais même plus require_once, non ?
Non pas nécessairement et même non tout court car illogique.


1) si tu as un fichier template pour générer une ligne de tableau tu vas
bien l'appeler dans une boucle while en require. Donc certainement pas
"once".
2) require_once est un mécanisme interne de php pour éviter que les
symboles ne soient définis plusieurs fois. Rien à voir avec la mécanique
de présentation.

C'est vrai que ca reste un système de templates mais mnt c'est php qui
effectue le chargement et le parsing du fichier au lieu que cela soie
à la charge du développeur.
Le développeur ne fait que l'orchestrer en appelant require( ), en effet.


l'impossibilité de faire des boucles avec un seul fichier.
Oui là, par-contre, il va falloir que je trouve quelque chose....



Découper. Inclure un minimum de structures de contrôle dans la
présentation.

C'est là que le dilemne arrive : j'ai $res=mysql_query(...) et j'ai géré
l'erreur potentielle.

Est-ce que je fais dans mon template de présentation globale :
while ($row=mysql_fetch_array($res))
require('tpl_ligne.txt');

ou est-ce que je mets une couche inutile qui commence par faire :
$presentation=array();
while($row=mysql_fetch_array($res))
$presentation[]=$row;

puis dans le template :
foreach($presentation ...
...

Perso je zappe la recopie inutile des données, mais il y en a que ça fait
grimper aux arbres...

a++;
JG


Avatar
Cleo
On bénéficie ainsi de la séparation Code/Présentation tout en
gardant un code efficace. Smarty permet aussi de cacher certaines
parties des pages et donc d'accélérer encore le traitement.


Mais à quoi bon utiliser des systèmes de cache implémentées en php alors
qu'il existe des solutions "bas niveau", totalement transparentes pour le
développeur comme eaccelerator, ou ZendOptimizer ?

--
Cléo

Avatar
gabriel
Alors tu auras seulement gagné le non ping-pong des données, mais tu fais
quand même un aller-retour pour des prunes. Je rappelle que header( )
envoie des données au NAVIGATEUR pour qu'il REDEMANDE une autre age, ce
qui dans 99% des utilisations actuelles est DEBILE.

ok, je vire le concept de header (qui vient de java en fait :

requestDispatcher etc...)
Merci pour l'explication qui fut très claire :)


Je n'ai pas dit ça. Je en suis pas capable de dire(1) quel est le coût
exact du parsing et de l'entrée en scripting, puis sortie du moteur etc...
La seule chose que j'en dis c'est que la quantité de données à mouliner
est la même, et que les manipulations de chaînes de caractères surtout à
coups de regexp si elles sont utilisées sont toujours coûteuses.
Il est vrai que le regexp au lieu du str_replace, ca se paye cher :)

(1) i.e. je n'ai jamais fait de benchs à ce sujet, mais ça doit bien
traîner qq part
Mal cherché, alors j'en ai fait un simple :
<html>

<head>
<title>Document sans titre</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body>
<?php
function getmicrotime()
{
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$startParam=getmicrotime();
for ($i=0;$i<1000;$i++){
?>
<b>
<?php
echo $i;
}
$endParam=getmicrotime();


?>
</b>

<?php
echo "<br>difference 1 is " . ($endParam - $startParam) ."<br>"; //
difference 1 is 0.0037000179290771

?>
<?php
$startParam=getmicrotime();
for ($i=0;$i<1000;$i++){
echo "<b>$i</b>";

}
$endParam=getmicrotime();
echo "<br>difference 2 is " . ($endParam - $startParam); //difference 2
is 0.16863203048706
?>
</body>
</html>
Je crois que j'ai du faire une erreur quelque part car la première
solution est plus rapide que la deuxième alors que l'écriture y est
volontairement torturée :)

oui. D'ailleus il faudrait plutôt require() au delà de php3...
Je dirais même plus require_once, non ?



2) require_once est un mécanisme interne de php pour éviter que les
symboles ne soient définis plusieurs fois. Rien à voir avec la mécanique
de présentation.
Là, aussi, merci :)


Découper. Inclure un minimum de structures de contrôle dans la
présentation.

Ah non, pas de mysql_query dans ma présentation : je passe par un dao

qui me masque la nature du result set en fait.
C'est là que le dilemne arrive : j'ai $res=mysql_query(...) et j'ai géré
l'erreur potentielle.

Est-ce que je fais dans mon template de présentation globale :
while ($row=mysql_fetch_array($res))
require('tpl_ligne.txt');

ou est-ce que je mets une couche inutile qui commence par faire :
$presentation=array();
while($row=mysql_fetch_array($res))
$presentation[]=$row;

puis dans le template :
foreach($presentation ...
...
Non, la il faut que je voie ce que mon dao me renvoie (positionner un flag en cas d'erreur, le premier élément du tableau contiendrait un code d'erreur, le reste les données : à creuser)

Perso je zappe la recopie inutile des données, mais il y en a que ça fait
grimper aux arbres...
Désolé, pas compris ?


a++;
JG
Merci pour tout, la discussion est passionante :)




Avatar
John GALLET
On bénéficie ainsi de la séparation Code/Présentation tout en
gardant un code efficace. Smarty permet aussi de cacher certaines
parties des pages et donc d'accélérer encore le traitement.


Mais à quoi bon utiliser des systèmes de cache implémentées en php alors
qu'il existe des solutions "bas niveau", totalement transparentes pour le
développeur comme eaccelerator, ou ZendOptimizer ?


J'ai l'impression que tu confonds deux types de cache. Et si c'est moi qui
ai mal compris ton propos, ça ne fait pas de mal de rappeler de temps en
temps ce qui va suivre.

A partir d'un fichier .php "en clair", équivalent d'un .java, il faut
d'abord parser/compiler les fichiers, pour donner de l'op-code, comme du
.class.

Cette opération qui est effectivement coûteuse peut parfaitement être mise
en cache pour un certain temps, ou carrément "définitivement" au sens il
faut relivrer en utilisant des compilateurs php comme par exemple le zend
encoder, ou ionCube, ou d'autres, et il est en effet alors nécessaire de
disposer du zend optimizer (gratuit) pour les relire. Notons au passage
que du coup, oui, on peut parfaitement livrer du php sans donner son code
source, on laisse juste en clair le fichier de config (en n'oubliant pas
de lui mettre l'extension .php, pas .inc ... hum).

Ensuite, le résultat de l'interprétation du script lui même, c'est à dire
le HTML généré, tout ou partie, peut parfaitement lui aussi être mis en
cache. On "gagne" alors encore plus parce qu'on renvoie en fait une page
statique, même pas de tentative de compilation du script. C'est de ce type
de cache que les systèmes de templates disposent le plus souvent : du
cache html, pas d'op-code. Les deux sont cumulables.

On peut aussi avoir un cache de requêtes à la base de données, et quand on
fait un SELECT le système de cache regarde s'il ne l'a pas déjà disponible
avant d'exécuter réellement la requête. Cache également cumulable avec les
deux précédents, en gérant intelligement les temps d'expiration des trois
sinon ça n' a pas d'intérêt, et en disposant d'un moyen de les purger si
on détecte un changement obligtoire des données (update/delete/insert).

Il va de soi (?) que toutes les applications ne sont pas prônes à utiliser
un système de cache. Mais certaines le sont totalement et n'ont de
"dynamiques" que le nom (changement de données une fois par heure si ce
n'est une fois par... an) et sont plus des CMS qu'autre chose.

Sans compter encore du cache interne mémoire du SGBDR lui même qui fait
que si tu lui demandes 10 fois la même chose sans laisser passer trop de
temps, la première fois sera beaucoup plus lente que les 9 suivantes (ce
qui est toujours le bazar et pour bencher une solution, et pour pour
savoir si une modification d'index accélère le select à optimiser).

Et ne parlons pas (tiens si) du cache tampon du ou des disques durs lui
même alimenté par le cache du file system en mémoire dont les dirty
pages sont descendues physiquement par l'appel à "sync" sous unix à
intervalles réguliers ;-)

Bref, des caches, c'est pas ce qui manque dans l'informatique. Ca me fait
penser qu'il faut que je remette les caches de mes pots de fleurs,
tiens...

HTH
JG


Avatar
John GALLET
Re,
Merci pour l'explication qui fut très claire :)
Et encore, je ne t'ai pas sorti la traditionnelle "MALC du livreur de

machine à laver".
Tiens au hasard :
http://groups-beta.google.com/group/fr.comp.lang.php/browse_thread/thread/ca2e5ca0ce8584a5/1a018f97203a761c
(passera pas le formattage 72 colonnes, mais j'ai la flemme)

Mal cherché, alors j'en ai fait un simple :
[snip]



Je crois que j'ai du faire une erreur quelque part car la première
solution est plus rapide que la deuxième alors que l'écriture y est
volontairement torturée :)


De toutes façons, il n'y a AUCUNE valeur statistique à ce genre de tests
en dessous, comme pour toutes statistiques, de 300 itérations, et de
préférence sur des fichiers de tail importante mélangent allègrement de
l'ascii "en dur" avec des appels à du code php en plein milieu.


Ah non, pas de mysql_query dans ma présentation : je passe par un dao
qui me masque la nature du result set en fait.
Un dao ? Connais pas. Un dahu, oui, mais un dao... ;-)


Oui, mais si ton fameux dahu^Wdao recopie les données du result set de la
base dans une structure locale (array en php, arraylist par exemple en
java) non seulement du bouffes deux fois la mémoire, mais tu perds ton
temps à faire des choses inutiles... C'est le prix de l'encapsulation.

Non, la il faut que je voie ce que mon dao me renvoie



Ce que, je m'en doute : une structure de données strictement équivalente à
celle qui revient du sgbd_fetch_bidule( ) exécuté sur tout le sgbdr_query(
), avec code d'erreur, et nombre de rangs.

La question c'est : comment. En schématisant comme un goret est-ce qu'on
te passe une copie ou un pointeur sur les raw data reçues (plus
précisement leur représentation en PHP car on a reçu un result set en C et
on a déjà bindé les structures de la base vers une structure en C pour
créer la variable PHP).

Désolé, pas compris ?
J'utilise directement le buffer de résultat en boucle while dans ma couche

de présentation si j'en ai besoin et que j'ai pas de post-traitements à
effectuer dessus. Sinon j'utilise carrément une couche d'abstraction genre
innodb.

Merci pour tout, la discussion est passionante :)
My pleasure.


a++;
JG


Avatar
kifran
Cleo wrote:
On bénéficie ainsi de la séparation Code/Présentation tout en
gardant un code efficace. Smarty permet aussi de cacher certaines
parties des pages et donc d'accélérer encore le traitement.



Mais à quoi bon utiliser des systèmes de cache implémentées en php alors
qu'il existe des solutions "bas niveau", totalement transparentes pour le
développeur comme eaccelerator, ou ZendOptimizer ?



eaccelerator

coucou c moaaaaa et je confirme :)


note 1: eaccelerator est le seul encodeur gratuit hein

note 2: on cherche des developeurs C costaud paske la team c
mieux que turckmmcache mais c pas encore ca hein

kifran alias franck34


Avatar
BLob
Dans mon cas j'utilise Smarty qui est un bon compromis entre moteur de
template totalement dynamique (ie le template est réévalué à chaque
fois) et php. Smarty, lorsqu'il voit une template pour la première
fois la compile et génère rien de moins qu'un fichier PHP de manière
transparente.
On bénéficie ainsi de la séparation Code/Présentation tout en
gardant un code efficace. Smarty permet aussi de cacher certaines
parties des pages et donc d'accélérer encore le traitement.


J'ai utilisé Smarty pendant longtemps. La séparation logique de
l'application / logique de la présentation (et non pas PHP / (X)HTML - XML
ou autre) est à mon avis la bonne approche. Mais je trouve que pour
certaines utilisations, Smarty fonctionne comme un carcan et je préfère
utiliser PHP comme langage de template.
- présentation d'un calendrier (ça va encore) ;
- présentation d'une structure en arborescence (système de fichiers,
présentation de forum à la "phorum") ;
- d'une manière générale, la présentation récursive d'éléments est rendue
plus complexe avec Smarty.

BLob

1 2