|
ulf-wendel.de   
|
|
 Home < PHP Projekte  < IT[X] Template  < Vergleich    |       |  
Print Version    
---
|
|
 Home 
 PHP Projekte 
    PHPDoc 
    Forms 
    IT[X] Template 
       Vergleich 
       API Docs 
    Userland Cache 
    Gtext 
    Menu 3 
    Columbo 
 PHP Schulung 
 Technik der Site 
 Büchertipps 
 Fotografie 
 Airbrush 
 Kontakt 
 Stuff 

Zeit gewinnen mit Templates

erschienen im Sonderheft PHP, 2001

Es ist paradox: Templates und Template-Klassen widersprechen einem der größten Vorteile von PHP, der direkten Einbindung in HTML-Dokumente, und dennoch sind sie beliebt. Was treibt Programmierer dazu, sich mit fremden Skripten zu beschäftigen und ihre Programme zu verlangsamen?

In Version 2 trug PHP noch den Namen "PHP/FI". FI steht für "Form Interpreter". Durch die Einbindung von PHP in das HTML-Formular gelingt es auch heute noch, bei geringen Programmierkenntnissen eine interaktive Seite zu erstellen. Das "PHP-Normalformular", welches auf sich selbst verweist und die Formularfelder mit übermittelten Werten vorbelegt, ist jedem Einsteiger bekannt.


PHP-Normalformular Top

<form action="<?php print $PHP_SELF?>" method="post">
  Vorname <input type="text" name="vorname" value="<?php print $vorname?>"><br>
  Nachname <input  type="text" name="nachname" value="<?php print $nachname?>">
  <p>
    <input type="submit" value="Namen speichern">
  </p>
</form>
    

Das Kontaktformular zählt zwar noch zum Tagesgeschäft, aber es stellt nicht mehr den Höhepunkt einer zeitgemäßen Website dar, ein Online-Shop entspricht schon eher dem aktuellen Kundenwunsch. Die Entwicklung eines vergleichsweise komplexen Online-Shops nimmt viel Zeit in Anspruch. Es rentiert sich schnell, ein flexibles Basissystem zu erstellen, welches den jeweiligen Anforderungen entsprechend angepasst wird. Jeder Kunde wird eigene Wünsche für die Produktdarstellung haben.

Anforderungsanalyse

Das Szenario verlangt vom Programmierer zwei Dinge:

  • Programmcode und HTML müssen voneinander getrennt werden
  • Das Design eines Artikels muss leicht veränderbar sein

Die erste Forderung ließe sich mit einem Layout-Manager erfüllen. Ein Layout-Manager ist ein Objekt, welches über eine Grundregel zur Anordnung von darzustellenden Elementen verfügt und an es übergebene Elemente in einem Zielformat, z.B. HTML, darstellt. Eine einfache Grundregel zur Darstellung von Elementen könnte lauten: Stelle jedes Element zentriert in einer eigenen Zeile dar. Der Informatiker wäre mit einem solchen Ansatz sehr zufrieden. Die erste Aufgabe ist erfüllt, es steht kein HTML im Programmcode, es entsteht ein HTML-Dokument, und mit einem leicht veränderten Layout Manager wäre gar PDF als Ausgabeformat möglich.

Leider droht dem Programmierer die Kündigung, weil es trotz der raffinierten Abstraktion nicht gelungen ist, die Darstellung von der Programmlogik zu trennen. Der Grafiker des Kunden, welcher weder PHP noch HTML, sondern nur seinen WYSIWYG-Editor beherrscht, ist mit dem Layout unzufrieden und kann keine Änderung vornehmen. HTML-Templates bieten sich als Ausweg an.


Beispieltemplate Top

...
<table>
  <tr>
    <td colspan="2"><h2>[ARTIKELBEZEICHNUNG]</h2></td>
  </tr>
  <tr>
    <td>Beschreibung</td>
    <td>[BESCHREIBUNG]</td>
  </tr>
  <tr>
    <td>Preis</td>
    <td>[PREIS_DM]</td>
  </tr>
  <tr>
    <td colspan="2">
       In den <a href="[URL_BESTELLUNG]"><b>Warenkorb</b></a> legen.
    </td>
  </tr>
</table>
...
    

Ein Template ist ein HTML-Dokument, welches Platzhalter enthält, die vom Programm durch Werte ersetzt werden. Die meisten Template-Klassen verwenden Platzhalter in der Form: [NAME_IN_GROSSBUCHSTABEN].

Hinweis: leider erlaubt der Framework dieser Website nicht die Ausgabe von geschweiften Klammern, bitte stellen Sie sich die eckigen Klammern "[]" als geschweifte Klammern "{", "}" vor.

Frei verfügbare Templatesysteme

Nachdem die Anforderungen geklärt sind und ein Lösungsansatz gefunden wurde, beginnt die Suche nach einer geeigneten Templateklasse. Google.com zeigt schnell zwei Gruppen von Templates.

(Eine dritte Gruppe von Templates mit Steueranweisungen und eigener Makrosprache wird nicht besprochen. Sie ähneln einem XSL Subset. Oft sind sie nicht als Open-Source verfügbar, sondern Teil eines kommerziellen Produkts. Ein sehr guter, von mir eingesetzter Open-Source Vertreter ist Smarty.)

Das einfache Template zur Produktdarstellung kommt ohne sich wiederholende Blöcke aus. EasyTemplate bietet sich an. Die Anwendung ist sehr einfach, da die API nur vier Funktionen umfasst.


EasyTemplate ist easy Top

<?php
// Template Klasse einbinden
require_once("EasyTemplate.php");

// Template Objekt von den angegebenem File erzeugen
$tpl = new EasyTemplate("produkt.html");

// Ersetzungen: Artikeldaten
$tpl->assign("ARTIKELBEZEICHNUNG""Easy Rider");
$tpl->assign("BESCHREIBUNG""Abenteuer, VHS, 91 min., FSK 16");
$tpl->assign("PREIS""14.95 DM");

// Ersetzungen: Shop Verwaltung
$tpl->assign("URL_BESTELLUNG""/cart.php?inc=3016");

// Template ausgeben, alternativ: print $tpl->easy_parse()
$tpl->easy_print();
?>      
    

Der Konstruktor lädt das Templatefile, dessen Name ihm übergeben wird. Variablenersetzungen werden mit boolean assign(string $varname, mixed $replacement) vorgenommen. Die Ausgabe erfolgt mit mixed easy_parse(void) oder boolean easy_print(void).

Laufzeitanalyse einfacher Lösungen

Intern verwendet EasyTemplate die Funktion str_replace() zur Variablenersetzung. Die Wahl der Funktion bestimmt die Geschwindigkeit der Templateklasse. Alle Templateklassen müssen das Templatefile laden und verwalten. Der Verwaltungsaufwand kann ab einer gewissen Zahl von Ersetzungen vernachlässigt werden, da sich ein konstanter Faktor ergibt. Wesentliche Geschwindigkeitsunterschiede können nur bei der Variablenersetzung auftreten.

PHP kennt drei Gruppen von Funktionen zur Stringersetzung. Einfache Ersetzungen mit den str*-Funktionen, Ersetzungen basierend auf POSIX-konformen Regulären Ausdrücken mit den ereg*-Funktionen und die preg*-Funktionen, die Perl-kompatible Reguläre Ausdrücke verarbeiten. Das Parsen des einfachen Artikeltemplates gelingt mit den str_replace() am schnellsten. Rund 20% langsamer sind ereg_replace() und ein mit Arrays aufgerufenes preg_replace(). Wirklich wichtig ist diese Erkenntnis jedoch nicht, selbst mein Entwicklungsserver, KROETE, ein AMD5x86-133 (etwa Pentium 60) benötigt nur 0.003 Sekunden für die Ersetzungen im Artikeltemplate. Kein guter Ausgangspunkt für Optimierungen!

EasyTemplate von Till Gerken ist für die gestellte Aufgabe die Template-Klasse der Wahl. Doch ein Kunde wäre kein echter Kunde, wenn keine neuen Anforderungen gestellt würden. Schnell wird klar, dass nicht alle Produkte im Online-Shop in einer Detailansicht dargestellt werden können. Bei Auswahl einer Artikelgruppe soll zunächst eine Listendarstellung aller enthaltenen Artikel erscheinen, bevor der Internetnutzer zur Detaildarstellung verzweigen kann.

Templates mit Blöcken

Der Grafiker gibt folgendes Layout für die Listendarstellung vor.


Designvorgabe Top

...
<table>
  <tr>
    <td colspan="3">Angebote aus der Artikelgruppe Mustergruppe</td>
  </tr>
  <!-- Anfang Listendarstellung eines Artikels -- >
  <tr>
    <td><a href="/cart.php"><img src="/cart.gif"></a></td>
    <td>Name des Artikels, Preis 99.99 DM</td>
    <td><a href="/detail.php">Detailansicht</a></td>
  </tr>
  <!-- Ende Listendarstellung eines Artikels -- >
</table>
...
    

Zu den ursprünglichen Anforderungen an das Programm kommt eine neue hinzu: Der <tr>-Container mit der Listendarstellung eines Artikels muß beliebig oft wiederholt werden können. Die zweite Gruppe der Template- Klassen mit Unterstützung für sich wiederholende Blöcke wird benötigt. Es konkurrieren X-, Fast- und die beiden PHPLib-Templates. (IT[X] wurde in der PHPLib entwickelt und später in PEAR übertragen.)

Die Features und APIs der einzelnen Templatesysteme unterscheiden sich etwas, im Wesentlichen bieten sie jedoch die gleiche Funktionalität. Somit entscheidet die Geschwindigkeit der Systeme über ihren Einsatz. Ein einfacher Test (siehe www.ulf-wendel.de/tpl_test.html) stellt die verschiedenen APIs dar und spaltet das Lager in zwei Gruppen. Wieder entscheidet die Wahl der Funktion zur Stringersetzung über Sieg und Niederlage.

  1. Integrated Template 4.13s (100.00%)
  2. PHPLib Template 4.77s (115.58%)
  3. XTemplate 8.94s (216.73%)
  4. FastTemplate 9.78s (237.08%)

Die mit den Perl-kompatiblen Regulären Ausdrücke (preg*-Funktionen) ausgestatteten Lösungen sind deutlich schneller und auch leistungsfähiger als die POSIX- konformen ereg*-Funktionen. FastTemplate wird zum SlowTemplate und kann nicht mit seinen Brüdern, den doppelt so schnellen PHPLib Templates, mithalten. Die ursprünglich aus der PHPLib stammenden Integrated Templates, kurz IT[X] genannt, gewinnen das Rennen knapp, weil die etwas andere Block-API einen Funktionsaufruf pro Schleifendurchlauf einspart.

Zu verdanken haben die PHPLib-Templatesysteme ihren Sieg Sascha Schumann. Er stattete in Version 3.0.7 die PCRE-Funktionen mit einem Cache aus. Der Cache speichert die Ergebnisse der C-Funktion regcomp(). Regcomp() kompiliert ein Suchmuster und überführt es in eine Form, die von der C-Funktion regexec() verstanden wird, welche die eigentliche Suche durchführt. Hinzu kommt, dass preg_replace() im Gegensatz zu ereg_replace() mit nur einem Funktionsaufruf gleich eine ganze Reihe Ersetzungen durchführen kann. Hierzu wird der Funktion statt eines einzelnen Suchmusters ein Array von Suchmustern und Ersatzwerten übergeben.

Testsieger preg*

Der Leistungsumfang der zwei schnellsten Systeme liegt so nah beisammen, dass die API über den Einsatz der einen oder anderen Lösung entscheidet. Während das Laden eines Templates und die Variablenzuweisungen in beiden Klassen sehr einfach sind, unterscheiden sich die Funktionen zum Blockhandling wesentlich.

Perl-Programmierer werden die Template-Klasse von Kristian Köhntopp schnell anwenden können, weil sie stark an FastTemplate erinnert, welches wiederum aus der Perl-Welt stammt. Anderen wird das Verständnis nur gelingen, wenn sie wissen, wie die Klasse arbeitet. Im Gegensatz zu IT[X] analysiert Template nicht das HTML Template, um herauszufinden, wie die gefundenen Blöcke ineinander verschachtelt sind. Die Klasse hat kein Wissen darüber, wie die Blöcke zusammengesetzt werden müsen, ohne Reihenfolge und Schachtelung zu zerstören.

Die Vorlage des Grafikers ist nur minimal zu verändern, damit sie verwendet werden kann. Der erste HTML- Kommentar wird gegen <!-BEGIN product_row -> ausgetauscht, der zweite entsprechend durch <!-END product_row -> ersetzt, letztendlich werden Platzhalter in der bekannten Form [VARNAME] eingefügt. Das Skript zur Bearbeitung benötigt nur wenige, jedoch gehaltvolle Zeilen.


PHPLib Templates Top

<?php
// Objekt erzeugen, Pfad zum Template angeben
tpl = new Template(TEMPLATE_ROOT);

// Template unter dem Handler "main" laden
$tpl->set_file( array("main"    => "template_detail.html") );
// Blockschachtelung wird beschrieben
$tpl->set_block("main""product_row""ROWS");

// Dummy Daten, wie sie aus mysql_fetch_array() stammen könnten
$daten = array(
                 
"URL_BESTELLUNG"  => "/cart.php?inc=3016",
                 
"URL_DETAIL"      => "/detail.php?art=3016",
                 
"BEZEICHNUNG"     => "Easy Rider",
                 
"PREIS"           => "14.95 DM"
             
);


// Inhalte zuweisen
for ($j 0$j ARTIKEL$j++) {
  
$tpl->set_var($daten);
  
$tpl->parse("ROWS""product_row"true);
}

$tpl->parse("MAIN""main");
$tpl->p("MAIN");
?>
    

Zunächst wird ein Objekt der Template-Klasse erzeugt. Durch den Konstruktor wird dem Objekt mitgeteilt, wo die HTML-Templates zu finden sind. Idealerweise ist dies in einer leicht veränderbaren Konstanten gespeichert. Anschließend wird das Template "template_detail.html" unter dem Handler "main" geladen.

Mit der Methode set_block() wird dem Objekt mitgeteilt, dass im Template "main" ein Block "product_row" existiert, der mehrmals dargestellt werden soll. Set_block() ersetzt nun intern den Block durch die Variable ROWS, die im dritten Parameter benannt wurde. Zu diesem Zeitpunkt ist der Inhalt von ROWS leer.

In einer Schleife werden die Artikeldaten dem Template-Objekt mit set_var() zugewiesen. Das Objekt wird anschließend mit parse() angewiesen, die übermittelten Daten im Block "products_row" einzusetzen und das Ergebnis dem Inhalt von ROWS hinzuzufügen. ROWS umfaßt mit jedem Schleifendurchlauf die Darstellung eines weiteren Artikels.

Statt für jeden Platzhalter set_var() aufzurufen, wird der Methode ein Array mit den Artikeldaten übergeben. Das Format von $daten entspricht dem typischen Rückgabewert einer Datenbankfunktion wie mysql_fetch_array().

Das Template-File selbst muss auch einer Variablen zugewiesen werden, bevor diese ausgegeben werden kann. Der parse()-Aufruf legt den Inhalt des Template-Files in der Variablen MAIN ab. Diese kann abschließend mit der Methode p(), für print, ausgegeben werden.

Die fein abgestufte API stellt dem Programmierer zwar ein mächtiges Werkzeug bereit, verlangt jedoch, dass dieser im Detail versteht, was passiert. Besonders bei komplexen Aufgaben mit mehreren Template-Files und tief verschachtelten Blöcken kann leicht Verwirrung entstehen.

Die Integrated Templates versuchen, hier Abhilfe zu schaffen. Zur Erledigung der gleichen Aufgabe benötigt der Anwender ein etwas kürzeres Skript. IT geht davon aus, dass alle Blöcke in einem Template-File enthalten sind. Es wird keine Möglichkeit bereitgestellt, die Blockschachtelung zu verändern und einen geparsten Block an mehreren Stellen im Template einzufügen.

Durch die Grundannahmen wird die API selbsterklärend. Wer nur selten die Einschränkungen überwinden muss, der sollte auf die Klasse Integrated Template Extension schauen. Sie enthält zusätzliche Methoden, die sogar mehr Funktionalität bieten, als die PHPLib-Templates zur Verfügung stellen.


IT Top

<?php
// Pfad zu den Templates angeben
$tpl = new IntegratedTemplate(TEMPLATE_ROOT);

// Template laden
$tpl->loadTemplatefile("template_detail3.html");
    
// Block auswählen und Daten zuweisen
$tpl->setCurrentBlock("product_row");
for (
$j 0$j ARTIKEL$j++) {
  
$tpl->setVariable($daten);
  
$tpl->parseCurrentBlock();
}

// Ergebnisse ausgeben
$tpl->show();
?>    
    

Mit diesem Basiswissen ist es möglich, HTML komplett aus dem Programmcode zu verbannen. Die Wiederverwendung von Skripten wird einfacher, und die lästigen Gespräche mit den Mäuseschubsern, auch Grafiker genannt, bleiben aus, sobald diese einmal verstanden haben, was ein Template ist.

Endlich gewinnt man Zeit, um eine eigene Templateklasse zu erfinden. Schließlich gehört es zum guten Ton in der PHP-Szene, über eine solche zu verfügen, wenn man schon kein Content Management System geschrieben hat ;). Einige CMS setzen zwar schon auf XML und XSLT, doch Templates sind verständlicher und auch sie lassen sich nicht nur zur Erstellung von HTML einsetzen.

<  ^  >

 Neues

 XML/XSLT Menu
 OOH-Form Rewrite

 PEAR Cache:
  SHM Container

 Suchstring Parser
 Buchrezensionen
 PEAR Cache:
  OutputCompression

 PEAR Menu Browser
 PEAR Menu Tutorial 
 PEAR Cache


 Tipp

Download Version:
oben rechts,
Download *.tar.gz
|
| --- |
|
  Top   |   <  ^  >   |   phpOpenTracker Statistik   |   URL: http://www.ulf-wendel.de/projekte/itx/vergleich.php   |   Stand: 16.01.2002   |   © Ulf Wendel   
|
| --- |

0.016 s Bearbeitungszeit, 0.002 s IT[X], 0.002 s Menu 3