Eigenes Templatesystem: { in HTML parsen.
lima-city → Forum → Programmiersprachen → PHP, MySQL & .htaccess
abfragen
array
beispiel
blocken
code
controller
datei
datum
designer
entwickler
erstellen
erstellung
frage
idee
logik
modeln
platzhalter
post
sagen
ziel
-
Hallo. :)
Ich arbeite derzeit an einem größeren Projekt. Da ich das designen hierbei jemand anderes überlassen will, und alles möglichst professional haben möchte, habe ich mir vorgenommen Programmiertechnisches und Design über ein templatesystem zu trennen. Ich weiß, adss viele Systeme wie z.B. Smarty existieren, allerdings finde ich diese zusammen alle viel zu überladen. :) Außerdem würde ich zu lernzwecken auch wirklich alles selbst realisieren. Ich möchte daher auch keine kompletten Scripts, sondern nur kleine Codezeilen (Funktionen) oder noch wichtiger; Ideenanstöße zum realisieren. ich möchte wie in phpBB 3 die Variablen, die in der templatedatei in { und } stehen parsen und ersetzen. :)
Also:
.. <body> <b>{TEXT}</b> </body>
Darin soll das {TEXT} so geparst werden, dass es z.B. durch die Variable $text ersetzt wird.
Ich könnte jetzt die gesamte Datei nicht inkludieren, sondern über file_get_content(); einlesen, über preg_match bzw. preg_replace diese parts ersetzen und dann ausgeben. Allerdings finde ich diese Methode sehr unsauber und extrem ressourcen verbrauchen.
Habt ihr noch andere Vorschläge, bzw. wie realisiren dass die großen Templatesysteme?
Vielen Dank schonmal. :) -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
guck dir mal das an: http://www.inside-php.de/tutorial/PHP-Fortgeschrittene-11/eigenes-Template-System.html
PS: Googeln hilft! -
edit:
@Vorposter:
Googlen hilft bei solch einem Ansatz eigentlich nicht. Fast alle Template "Engines" sind so aufgebaut wie Smarty..
*Keks_geb*
Deinen Ansatz finde ich gut!
Erst einmal solltest du dir überlegen, wie du logische Probleme in den HTML Dateien lösen willst.
Als Anregung:
Eine Begrüßung eines weiblichen/männlichen Users.
In der HTML Datei:
"Hallo lieber {CURRENT_USER}"
Eine unschöne Formulierung entsteht, wenn ein weiblicher Benutzer die Seite besucht.
Nun könnte man das "lieber" direkt in der PHP Datei nach dem Auslesen des Usernamens in einen String USER_GREETING schreiben.
Dann hätte man aber zwei Variablen "CURRENT_USER" und "USER_GREETING", wobei in beiden der Username steht. => Redundanz in den Variablen.
Das kann man jetzt noch bisschen ausführen, aber das würde den Beitrag sprengen. :-)
Letztendlich wirst du zu der Auffassung kommen, dass es logischer und effizienter ist, den Usernamen und das Geschlecht in einer Variable zu speichern.
Wie löst man jetzt das logische Problem in der HTML Datei?
Man könnte es wie Smarty machen und "if"-Abfragen anbieten etc. und die nachher wieder in PHP Code übersetzen und...
Man könnte... :)
Elegenater finde ich es, wenn man in der HTML Datei lediglich Alternativen _anbietet_.
Z.B. zum obigen Beispiel:
"Hallo [female_greeting]liebe[/female_greeting] [male_greeting]lieber[/male_greeting] {CURRENT_USER}"
Wie du siehst habe ich Bereiche (oder auch Blöcke) in der HTML Datei ausgezeichnet.
Jetzt steht dem PHP Script frei, ob es beide Blöcke anzeigen will, nur einen oder keinen Block.
Dadurch kann man sowohl If-Abfragen, als auch Schleifen realisieren.
Durch die einfachen Variablen kann man "includes" und das Einfügen von Variablen realisieren.
Somit eigentlich alles, was notwendig ist.
Kurzer Exkurs bezgl. der Schleifen:
Man liest den Block aus dem HTML Dokument aus speichert ihn z.B. in temp.
Initialisiert sich eine weitere Variable z.B. content.
Nun ruft man die Schleife auf.
Bei jedem Durchlauf werden die Platzhalter in temp mit den Variablen aus dem jeweiligen Schleifendurchlauf ersetzt. Das Ergebnis wird an content angehangen.
Beispiel:
$user = array (0 => array ('username' => 'lucas'), 1 => array ('username' => 'sbody')); // z.B. aus der Datenbank $tmp = $myView -> getBlock('user_table.tpl', 'user_table'); // z.B. "[user_table]<tr><td>%username%</td></tr>[/user_table]" $content = ''; foreach ($user as $id => $dataset) { $content .= $myView -> replaceArray($tmp, $dataset); // returns "<tr><td>".$array[__]['username'][."</td></tr>" }
Ich poste jetzt mal meine Template Klasse (de facto zwei Klassen).
Bei Interesse kannst du gerne durchschauen oder Teile verwenden.
<?php abstract class abstrView { protected $vCache; public function __construct () { $this -> vCache = array (); cc_loadExtension (7); $this -> autoload (); return (true); } protected function autoload () { return (true); } public function getFile ($pFile) { if (preg_match('/[a-z0-9\-_\/]/i', $pFile)) { if (isset ($this -> vCache[$pFile])) { return ($this -> vCache[$pFile]); } else { $path = $GLOBALS['_PATH']['dir']['tpl'].$pFile.'.'.$GLOBALS['_CONF']['tpl-ext']; if (file_exists ($path)) { $this -> vCache[$pFile] = file_get_contents ($path); return ($this -> vCache[$pFile]); } else { trigger_error ('Die Template-Datei "'.htmlentities ($path).'" existiert nicht'); return (false); } } } else { trigger_error ('Der Name der Template-Datei "'.htmlentities ($pFile).'" enthält nicht zugelassen Zeichen.'); return (false); } } public function getHeader () { $data = ''; foreach ($GLOBALS['_CC']['HTTP_Response'] as $value) { $data .= $value."\r\n"; } return ($data); } public function setHeader ($pData) { $GLOBALS['_CC']['HTTP_Response'][] = $pData; return (true); } public function sendData () { return (true); } public function __destruct () { return (true); } } ?>
<?php class HTML_View extends abstrView { public function assignString ($pData, $pWildcard, $pOverwrite = false) { if (isset ($GLOBALS['_TPL']['wildcards'][$pWildcard]) && $pOverwrite === false) { $GLOBALS['_TPL']['wildcards'][$pWildcard] .= $pData; } else { $GLOBALS['_TPL']['wildcards'][$pWildcard] = $pData; } return (true); } public function assignArray ($pData) { if (is_array ($pData)) { $GLOBALS['_TPL']['wildcards'] = array_merge ($GLOBALS['_TPL']['wildcards'], $pData); return (true); } else { trigger_error ('Der übergeben Parameter ist kein Array.'); return (false); } } public function file ($pFile, $pWildcards) { return ($this -> replaceArray ($this -> getFile ($pFile), $pWildcards)); } public function getBlock ($pString, $pBlock) { return (preg_replace ('/(.*?)\['.preg_quote ($pBlock, '/').'\](.*?)\[\/'.preg_quote ($pBlock, '/').'\](.*?)/Usi', '\2', $pString)); } public function getBlockFromFile ($pFile, $pBlock) { return (preg_replace ('/(.*?)\['.preg_quote ($pBlock, '/').'\](.*?)\[\/'.preg_quote ($pBlock, '/').'\](.*?)/Usi', '\2', $this -> getFile ($pFile))); } public function replaceString ($pData, $pWildcard, $pValue) { $pValue = preg_replace ('/[$\x5c]/', '\\\\$0', $pValue); $pData = preg_replace ('/'.preg_quote ($GLOBALS['_CONF']['tpl-wc-left-delimiter'].$pWildcard.$GLOBALS['_CONF']['tpl-wc-right-delimiter'], '/').'/Us', $pValue, $pData); $pData = preg_replace ('/'.preg_quote ($GLOBALS['_CONF']['tpl-block-left-delimiter'].$pWildcard.$GLOBALS['_CONF']['tpl-block-right-delimiter'], '/').'(.*?)'.preg_quote ($GLOBALS['_CONF']['tpl-block-left-delimiter'].'/'.$pWildcard.$GLOBALS['_CONF']['tpl-block-right-delimiter'], '/').'/Us', $pValue, $pData); return ($pData); } public function replaceArray ($pData, $pArray) { if (is_array ($pArray)) { if (isset ($pArray[0]) && is_array ($pArray[0])) { trigger_error ('Der zweite Parameter darf kein mehrdemensionales Array sein'); return (false); } else { foreach ($pArray as $wildcard => $value) { $pData = $this -> replaceString ($pData, $wildcard, $value); } return ($pData); } } else { trigger_error ('Der zweite Parameter muss ein Array sein'); return (false); } } public function getData () { $data = $GLOBALS['_TPL']['template']; if (count ($GLOBALS['_TPL']['local-wildcard']) > 0) { $data = $this -> replaceArray ($data, $GLOBALS['_TPL']['local-wildcard']); } if (count ($GLOBALS['_TPL']['wildcard']) > 0) { $data = $this -> replaceArray ($data, $GLOBALS['_TPL']['wildcard']); } if (count ($GLOBALS['_TPL']['global-wildcard']) > 0) { $data = $this -> replaceArray ($data, $GLOBALS['_TPL']['global-wildcard']); } return ($data); } public function sendData () { header ($this -> getHeader ()); print ($this -> getData ()); return (true); } } ?>
Beitrag zuletzt geändert: 20.10.2010 13:18:56 von nikic -
Erstmal vorweg: Nimm einfach ein fertiges. Ich habe zu Anfang auch nur mit meiner eigenen simplen Template-Klasse gearbeitet, durfte aber schnell merken, dass so ein Platzhalter einfügen und ne if-Abfrage einfach nicht genug sind. Besonders empfehle ich dir Twig, da es deutlich schneller ist als vergleichbare Projekte (Smarty ist ja wohl mal der letzte Dreck) und zudem bestimmte Features bietet, die sehr bequem sind, beispielsweise Template-Vererbung.
Wie es die großen machen: Das Template wird durch einen Tokenizer gejagt, der Tokenstream wird in einen Syntaxtree konvertiert und anschließend zu PHP kompiliert und gecacht. D.h. aus deinem Template wird eigentlich wieder PHP Code gemacht. Diese Herangehensweise wird genutzt, da sie super schnell ist - das Template wird ein mal (langsam) kompiliert und ist anschließend immer griffbereit (und wenn man das noch mit APC verbindet, dann geht es natürlich noch schneller, weil die Opcodes deines Templates schon im Speicher sind). Komplexe Verschachtlungen und Konstrukte on-the-fly bei jedem Seitenaufruf aufzulösen ist im Vergleich damit natürlich unnötig langsam.
Beitrag zuletzt geändert: 29.7.2010 15:35:06 von nikic -
nikic schrieb:
Erstmal vorweg: Nimm einfach ein fertiges. Ich habe zu Anfang auch nur mit meiner eigenen simplen Template-Klasse gearbeitet, durfte aber schnell merken, dass so ein Platzhalter einfügen und ne if-Abfrage einfach nicht genug sind. Besonders empfehle ich dir Twig, da es deutlich schneller ist als vergleichbare Projekte (Smarty ist ja wohl mal der letzte Dreck) und zudem bestimmte Features bietet, die sehr bequem sind, beispielsweise Template-Vererbung.
Wie es die großen machen: Das Template wird durch einen Tokenizer gejagt, der Tokenstream wird in einen Syntaxtree konvertiert und anschließend zu PHP kompiliert und gecacht. D.h. aus deinem Template wird eigentlich wieder PHP Code gemacht. Diese Herangehensweise wird genutzt, da sie super schnell ist - das Template wird ein mal (langsam) kompiliert und ist anschließend immer griffbereit (und wenn man das noch mit APC verbindet, dann geht es natürlich noch schneller, weil die Opcodes deines Templates schon im Speicher sind). Komplexe Verschachtlungen und Konstrukte on-the-fly bei jedem Seitenaufruf aufzulösen ist im Vergleich damit natürlich unnötig langsam.
So funktioniert es auch bei phpBB3, denke ich. Die Dateien im Cache sind immer PHP Dateien. Du meinst also, das Template wird geparst und mit der PHP-Datei zusammengefügt, so dass die gecachte Datei keine Trennung mehr von Inhalt und Programmierung enthält? Dann stellt sich noch die Frage, wie man dann dem Nutzer anstatt der richtigen Datei die gecachte übergibt. Aber das nur in der Theroie. Ich denke ich werde ein fertiges benutzen. :) -
Ein fertiges zu benutzen ist eine gute Entscheidung ;) [Ich empfehle Twig nochmals :D]
Du meinst also, das Template wird geparst und mit der PHP-Datei zusammengefügt, so dass die gecachte Datei keine Trennung mehr von Inhalt und Programmierung enthält?
Nein, das wäre glaube ich sehr aufwändig. Alles was gemacht wird ist das Template in PHP-Code zu konvertieren. Ein "{{ variable + 7 }}" wird dann vielleicht zu einem "echo isset($data['variable']) ? $data['variable'] : null + 7".
Dann wird dieser generierte PHP Code in eine Datei geschrieben und diese wird anschließend required. Wenn du wissen willst wie das genau abläuft kannst du mal den Code von einem generierten Twig-Template ansehen ;) Dann weißt du, was ich meine. -
Okay danke. :)
Ich werde mir Twig mal anschauen, vor allem, weil es gute Performance verspricht, und dass es ist, was ich am meisten brauche.:)
Kannst du mir denn sagen, wie groß ich ein Projekt verändern muss, um es an Twig anzupassen? Sonst würde ich mir noch ein simpleres suchen. -
Schwer zu sagen. Ich mache es so, dass ich eine Variable R::$tplName für den Template Namen habe und eine Variable R::$tpl für die Daten, die das Template bekommen soll. Dank der Template-Vererbung ist das auch schon alles was man braucht. Die Scripts selbst müssen immer nur das R::$tpl Array füllen und einen R::$tplName angeben. Den Rest erledigt meine index.php. Die erstellt dann ein Twig_Environment, läd das angegebene Template und rendert es. Also, so viel Umstellung sollte es nicht sein ;)
€dit: Das R:: ist nur da, um die Variablen global zugänglich zu machen. Davon lass dich nicht stören.
Beitrag zuletzt geändert: 30.7.2010 10:33:52 von nikic -
nikic schrieb:
Erstmal vorweg: Nimm einfach ein fertiges. Ich habe zu Anfang auch nur mit meiner eigenen simplen Template-Klasse gearbeitet, durfte aber schnell merken, dass so ein Platzhalter einfügen und ne if-Abfrage einfach nicht genug sind. Besonders empfehle ich dir Twig, da es deutlich schneller ist als vergleichbare Projekte (Smarty ist ja wohl mal der letzte Dreck) und zudem bestimmte Features bietet, die sehr bequem sind, beispielsweise Template-Vererbung.
Wie es die großen machen: Das Template wird durch einen Tokenizer gejagt, der Tokenstream wird in einen Syntaxtree konvertiert und anschließend zu PHP kompiliert und gecacht. D.h. aus deinem Template wird eigentlich wieder PHP Code gemacht. [...]
Warum schreibt man die Template Dateien nicht direkt in PHP und lässt die mit parsen?
Ich finde die Idee da hinter komisch.
Das Ziel ist es die Logik in das Model zu integrieren und nicht in die View.
Ergo sollte im HTML Code keine Logik, wie z.B. Schleifen, Abfragen etc. auftauchen.
Was bleibt sind einfache Platzhalter die durch Informationen gefüllt werden und definierte Bereich/Blöcke die ausgeblendet werden können, einmal oder auch vielfach ausgegeben werden können.
Die Logik dafür sollte allerdings im PHP Script sitzen und nicht im HTML Dokument.
Ich halte die Idee auch für ein unnötiges Sicherheitsrisiko aus dem Code vom Designer PHP Code zu erstellen.
Die Idee den HTML Code mit Hilfe des Tokenizer in einen Syntaxtree zu konvertieren finde ich an sich gut.
Aber den Schritt den Syntaxtree in PHP Code umzuwandeln würde ich nicht gehen.
An Stelle dessen könnte das Model der View sagen, welche Knoten im Syntaxtree es so belassen soll, welches es vervielfältigen und welches es löschen soll.
Wäre das nicht viel einfacher und auch effizienter?
Beitrag zuletzt geändert: 1.8.2010 21:43:49 von lucas9991 -
Warum schreibt man die Template Dateien nicht direkt in PHP und lässt die mit parsen?
Weil PHP als Template-Sprache nicht sonderlich geeignet ist. Es macht einfach einen Unterschied, ob man `<?php echo htmlspecialchars($variable, ENT_QUOTES); ?>` schreibt oder `{{ variable|e }}`. Letzteres schreibt sich einfacher und ist auch schneller zu durchschauen. Templatesysteme sind halt darauf ausgelegt das zum Erstellen eines Templates Notwendige möglichst einfach zu gestalten und gleichzeitig die Gefahr der Ausführung von reinem PHP-Code zu eliminieren. Nicht jeder, der Tempates schreibt ist jahrelanger PHP Entwickler, der genau weiß, was er tun sollte und was nicht. Daher wäre es unklug einen Designer, der eigentlich keinen blassen Schimmer von PHP hat einfach mit der ganzen Macht von PHP alleine lassen. Ein falsches Anführungszeichen und schon wird der Code von der Shell ausgeführt und nicht nur ausgegeben.
Das Ziel ist es die Logik in das Model zu integrieren und nicht in die View.
Du meinst in den Controller, oder?
Ich würde nicht sagen, dass das das Ziel ist. Ziel ist es viel mehr den HTML Code aus den PHP-Dateien zu bekommen ;) Vorteil davon ist, dass man die View-Komponente dann sehr unabhängig vom Controller ändern kann. D.h. ein Designer kann sich um die Views kümmern ohne jemals an dem zugehörigen Controller zu fummeln oder ihn gar zu sehen. Ein weiterer Vorteil ist, dass man somit einfach für verschiedene Medien verschiedene Views erstellen kann. Wenn man nun einmal irgendwelche Daten für HTML-Ausgabe an den Browser haben will und nochmal als RSS-Feed, dann wird das mit HTML-Code im Controller sehr schwer ;)
Ich halte die Idee auch für ein unnötiges Sicherheitsrisiko aus dem Code vom Designer PHP Code zu erstellen.
Es ist auch ein verdammt großes Sicherheitsrisiko PHP zu benutzen. Am besten sollte man den Server einfach ausschalten, dann passiert ganz sicher nichts ;)
Mal ernsthaft, jede Software kann Bugs enthalten. Man geht halt in erster Linie davon aus, dass sie keine enthält. Und ich kann mir echt nicht vorstellen, wo man in einem Twig-Template PHP-Code einschleusen könnte. (Bei Smarty könnt ich mir das schon vorstellen, Smarty ist da etwas weltoffener :D)
Die Idee den HTML Code mit Hilfe des Tokenizer in einen Syntaxtree zu konvertieren finde ich an sich gut.
Missverständnis. Ich meine nicht den PHP-Tokenizer, sondern einen eigenen, der Template-Sprache angepassten. Mit dem PHP eigenen könnte man denke ich Templates eher schlecht tokenizen.
Wäre das nicht viel einfacher und auch effizienter?
Nein, effizienter wäre es nicht. Per Definition ist der kompilierte PHP-Code schneller als alles, was du on-the-fly machen kannst ;) -
hmm, ich hab zwar keine direkte ahnung warum solche Templatesysteme immer angepriesen werden, aber ich glaub das werd ich auch nicht verstehen. aber ich hab mich auch weder mit smarty noch twig noch was anderem beschäftigt.
ich hab für mich selbst und meine eigenen systeme 2 einfache klassen geschrieben. eine design und eine templateklasse.
theoretisch gesehn sind sie fast das selbe, haben aber im flush nochn paar aufgaben. die designklasse zb scant im design ebenfalls noch nach angeforderten boxen. also es gibt halt nen ordner mit ner menge verschiedenen boxen drin, und in meinem template würd man zb mit einem einfachen {{box_login}} an dieser stelle aus dem boxenordner die datei "login.box.php" laden und den inhalt genau in diese box tun. hat den vorteil dass ich nich immer erst im PHP code die boxen laden muss, sondern sie so variabel je nach design und je nach gebrauch geladen werden. angedacht war das gleiche auchmal für standartsprach elemente zu machen mit {{speech_submit}} zb nen submitbutton zu betitulieren, aber sowas hab ich noch nich.
ansonsten sind design und templateklasse fast gleich und funzen (ich weiß, ist eig nen scheiß mechanismus) über das einlesen einer datei und ersetzen von geegben ausdrücken. mit $tpl->add_key('EXPLODE', $content); würd man zb dem schlüssel {{EXPLODE}} den kompletten wert der variable $content übergeben/ersetzt. im destructor setz ichs denn zusammen (wenn das noch nicht geschehen ist, kann man/muss man teilweise manuell steuern), und der flushed es dann auch.
also mein prinzip zusammengefasst: datei einlesen, markierte stellen durch den controler ersetzen, flushen.
mir ist klar dass ich für gewisse teile (tabellenerstellung, listenerstellung letztendlich wieder den controler bemühen muss, ist nichts gutes, aber ich komm damit super zurecht. ich selbst zumindest, kommt ja auch von mir^^
vorbild war des TPL system von ilchClan, allerdings kann das noch ein paar dinge besser ein paar schlechter (bin noch nich so weit als dass ich einen eigenen algorithmus für listenprasing im TPL selbst habe). es läuft gut und schnell, ist leicht anzupassen und direktes negatives hab ich auch noch nicht festgestellt. allerdings habe ich auch noch nie riesige projekte gehabt.
wenn PHP durchprasen so schnell ist kann man aber doch wirklich direkt die templates in PHP schreiben nen heredoc/echo system wird man da bestimmt hinkriegen, es ist nur sehr unübersichtlich.
ich weiß nich das dagegen spricht, loade ne datei, replace die jeweiligen fragmente, flush it. natürlich gibts wesendlich bessere möglichkeiten, aber um daten und dateiarbeiten anfänglich zu lernen ists nen simples und interessantes projekt besonders wenn mans immer wieter ausfeilt eben mit variablem boxenload, speechstrings, listdesigns in templates oder sonst mehr. für daten und dateiverarbeitung ists schön zu lernen
trotzallem muss das rad wirklich nicht neu erfunden werden, es gibt genug template systeme, allerdings ist manchmal die frage ob es nicht ein wenig überdimensioniert ist. und wo ich kritisch entgegenstehe ist, das ich mich damit eben noch zu wenig beschäftigt habe.
soweit mal die meinung eines noobs^^ aber vllt ja was interessantes -
Zu dem Thema will ich auch mal meinen Senf dazu geben, ich hab da nämlich auch mal was gemacht, das ich auch effektiv eingesetzt habe, aber irgendwie bin ich von template-engines trotzdem nicht worklich überzeugt, da PHP ja selbst schon wie eine TE aufgebaut ist.
Trotzdem will ich dir hier mal mein Script zeigen, da kannst du auch die delimiter so einstellen wie du willst und sonderlich "überladen" ist sie ziemlich sicher nicht, sie kann nämlich wirklich nur suchen-finden-ersetzten, allerdings dafür in eine beliebige Ebenentiefe, wenn du dir mal ein Beispiel ansehen willst, hier ist die komplette TE + Beispiel:
http://felix.fh-n.de/template-engine/v1/code.php -
nikic schrieb:
Warum schreibt man die Template Dateien nicht direkt in PHP und lässt die mit parsen?
Weil PHP als Template-Sprache nicht sonderlich geeignet ist. Es macht einfach einen Unterschied, ob man `<?php echo htmlspecialchars($variable, ENT_QUOTES); ?>` schreibt oder `{{ variable|e }}`. Letzteres schreibt sich einfacher und ist auch schneller zu durchschauen. Templatesysteme sind halt darauf ausgelegt das zum Erstellen eines Templates Notwendige möglichst einfach zu gestalten und gleichzeitig die Gefahr der Ausführung von reinem PHP-Code zu eliminieren. Nicht jeder, der Tempates schreibt ist jahrelanger PHP Entwickler, der genau weiß, was er tun sollte und was nicht. Daher wäre es unklug einen Designer, der eigentlich keinen blassen Schimmer von PHP hat einfach mit der ganzen Macht von PHP alleine lassen. Ein falsches Anführungszeichen und schon wird der Code von der Shell ausgeführt und nicht nur ausgegeben.
Ich meinte die Frage etwas anders.
Mir ist schon klar, warum man HTML Code auslagert, aber ich finde es unlogisch, HTML Code auszulagern, ihn mit Pseudo Code anzureichern und diesen dann letztendlich in PHP Code zu übersetzen und dann den HTML Code mit PHP Code wieder zu parsen.
Das Prinzip, wie du es beschrieben hattest.
Das Ziel ist es die Logik in das Model zu integrieren und nicht in die View.
Du meinst in den Controller, oder?
Ich würde nicht sagen, dass das das Ziel ist. Ziel ist es viel mehr den HTML Code aus den PHP-Dateien zu bekommen ;) Vorteil davon ist, dass man die View-Komponente dann sehr unabhängig vom Controller ändern kann. D.h. ein Designer kann sich um die Views kümmern ohne jemals an dem zugehörigen Controller zu fummeln oder ihn gar zu sehen. Ein weiterer Vorteil ist, dass man somit einfach für verschiedene Medien verschiedene Views erstellen kann. Wenn man nun einmal irgendwelche Daten für HTML-Ausgabe an den Browser haben will und nochmal als RSS-Feed, dann wird das mit HTML-Code im Controller sehr schwer ;)
[/quote]
Ich meine die so genannte "Business Logic" des Models.
Nach meiner Logik, bieten die Views einfach Blocks und Platzhalter an, die ersetzt werden können.
Also es existiert ein Controller A, ein Model A und ein Pool von View.
Model A wird mitgeteilt, dass es die View X aus dem Pool nutzen soll. Das Model liest dann die Daten aus und ersetzt bestimmte in dem Model definierte Blocks und Platzhalter.
Ob View X jetzt eine HTML Datei, ein RSS Feed oder sonst was ist, ist relativ wurst. Hauptsache es ist eine Textdatei. Über binär Dateien habe ich mir bisher noch keine Gedanken gemacht. Ist aber sicherlich eine Schwäche.
Ich halte die Idee auch für ein unnötiges Sicherheitsrisiko aus dem Code vom Designer PHP Code zu erstellen.
Es ist auch ein verdammt großes Sicherheitsrisiko PHP zu benutzen. Am besten sollte man den Server einfach ausschalten, dann passiert ganz sicher nichts ;)
Mal ernsthaft, jede Software kann Bugs enthalten. Man geht halt in erster Linie davon aus, dass sie keine enthält. Und ich kann mir echt nicht vorstellen, wo man in einem Twig-Template PHP-Code einschleusen könnte. (Bei Smarty könnt ich mir das schon vorstellen, Smarty ist da etwas weltoffener :D)
Sicherheit ist immer relativ, aber man kann trotzdem versuchen mögliche Sicherheitslücken auf ein Minimum zu reduzieren.
Gerade bei Code, der dynamisch erzeugt und dann geparst wird, sehe ich auf jeden Fall Gefahren.
Die Idee den HTML Code mit Hilfe des Tokenizer in einen Syntaxtree zu konvertieren finde ich an sich gut.
Missverständnis. Ich meine nicht den PHP-Tokenizer, sondern einen eigenen, der Template-Sprache angepassten. Mit dem PHP eigenen könnte man denke ich Templates eher schlecht tokenizen.
Wäre das nicht viel einfacher und auch effizienter?
Nein, effizienter wäre es nicht. Per Definition ist der kompilierte PHP-Code schneller als alles, was du on-the-fly machen kannst ;)
Es ging mir nicht um die Effizienz des komplimierten PHP-Codes, sondern um die Effizienz zur Ersrtellung von diesem. -
lucas9991 schrieb:
Ich meinte die Frage etwas anders.
Mir ist schon klar, warum man HTML Code auslagert, aber ich finde es unlogisch, HTML Code auszulagern, ihn mit Pseudo Code anzureichern und diesen dann letztendlich in PHP Code zu übersetzen und dann den HTML Code mit PHP Code wieder zu parsen.
Das Prinzip, wie du es beschrieben hattest.
Naja, was findest du daran unsinnig? Das ganze herumgekompiliere dient eigentlich nur der Geschwindigkeitsoptimimerung. Das Ausführen des Templates als PHP Code ist nunmal schneller als "live" Interpretierung des Templates.
Ich meine die so genannte "Business Logic" des Models.
Interessanter Ansatz Logik ins Modell zu packen. Das hab ich bis jetzt noch in keinem MVC Framework gesehen. Normalerweise ist die gesamte Logik im Controller.
Nach meiner Logik, bieten die Views einfach Blocks und Platzhalter an, die ersetzt werden können.
Nun, ich finde nach deiner Logik könnte man auch die Blocks weglassen und nur bei den Platzhaltern bleiben. Blocks sind ja sowas wie if-Abfragen bei dir, oder? Und wenn das nicht mal Logik ist! Die gehört in den Controller! (Oder Model bei dir.)
Ob View X jetzt eine HTML Datei, ein RSS Feed oder sonst was ist, ist relativ wurst. Hauptsache es ist eine Textdatei.
Nun, bei dir ist es gerade nicht wurst. Das liegt daran, dass du HTML Code im Model hast. Wenn ich jetzt einen RSS-Feed mit dem selben Inhalt aber anderem Code erstellen will, müsste ich den Model-Code duplizieren - einmal für HTML, einmal für RSS. Mit Templating würde ich einen Dateinamen ändern und einen MIME-Type.
Sicherheit ist immer relativ, aber man kann trotzdem versuchen mögliche Sicherheitslücken auf ein Minimum zu reduzieren.
Gerade bei Code, der dynamisch erzeugt und dann geparst wird, sehe ich auf jeden Fall Gefahren.
Nun, ich nicht. Man müsste sich als Entwickler schon äußerst dumm anstellen, um das Ausführen von beliebigem Code über ein Template zu erlauben. (Zum Beispiel in dem man eine class Evil { public function evil($code) { eval($code); } } erstellt.)
Es ging mir nicht um die Effizienz des komplimierten PHP-Codes, sondern um die Effizienz zur Ersrtellung von diesem.
Die Effizienz bei der Erstellung von diesem ist unbedeutend. Der Code wird gecacht, d.h. es wird ein mal langsam kompiliert, danach ist das Template immer in kompiliertem Zustand griffbereit. Bei seriösen Projekten sind zusätzlich sogar OPCODEs des Templates im Arbeitsspeicher, da seriöse Leute bekanntlich APC nutzen ;)
Beitrag zuletzt geändert: 4.8.2010 0:52:42 von nikic -
nikic schrieb:
Naja, was findest du daran unsinnig? Das ganze herumgekompiliere dient eigentlich nur der Geschwindigkeitsoptimimerung. Das Ausführen des Templates als PHP Code ist nunmal schneller als "live" Interpretierung des Templates.
Ich finde unsinnig, weil es in meinen Augen ein Widerspruch ist.
Auf der eine Seite sagst du, du würdest PHP und HTML Code trennen. Auf der anderen Seite erfolgt diese Trennung aber nur indirekt durch eine weitere Abstraktionsschicht (dem Pseudo Code).
Das ist so, als wenn man drei Personen A, B und C hat. A und B wird verboten miteinander zu reden. Dann sagt A zu C etwas und C sagt es weiter zu B, wobei alle im gleichen Raum sitzen...
Interessanter Ansatz Logik ins Modell zu packen. Das hab ich bis jetzt noch in keinem MVC Framework gesehen. Normalerweise ist die gesamte Logik im Controller.
Da scheiden sich häufig die Geister. Bei PHP Anwendungen finde ich es so allerdings nützlich, da die eigentliche Daten in der Regel in Datenbanken liegen.
Nun, ich finde nach deiner Logik könnte man auch die Blocks weglassen und nur bei den Platzhaltern bleiben. Blocks sind ja sowas wie if-Abfragen bei dir, oder? Und wenn das nicht mal Logik ist! Die gehört in den Controller! (Oder Model bei dir.)
Blöcke sind per se keine if-Abfragen. Es sind einfach nur extra ausgezeichnete Textabschnitte.
Extra ausgezeichnet, damit sie ausgelesen werden können und manipuliert werden können.
Wie sie manipuliert werden kann man in der View aber nicht erkennen, das hängt ganz vom Model (oder Controller bei dir ) ab.
Nun, bei dir ist es gerade nicht wurst. Das liegt daran, dass du HTML Code im Model hast. Wenn ich jetzt einen RSS-Feed mit dem selben Inhalt aber anderem Code erstellen will, müsste ich den Model-Code duplizieren - einmal für HTML, einmal für RSS. Mit Templating würde ich einen Dateinamen ändern und einen MIME-Type.
HTML Code ist nicht im Model. Das Erstellen von RSS Feeds oder HTML geschieht über ein Model.
Das Template vom HTML Code oder RSS Feed haben wie oben gesagt Blöcke.
Das Auslesen der Daten(z.B. aus der DB) im Model geschieht gleich und auch das manipulieren der Blöcke.
Allerdings werden je nach Type evtl. noch Stringmanipulationen durchgeführt o.ä.
Also die Daten werden im Model für den entsprechenden Datentyp angepasst.
Das mache ich, weil ich z.B. nicht möchte, dass erst in der View der HTML Code aus Strings escaped wird.
Nun, ich nicht. Man müsste sich als Entwickler schon äußerst dumm anstellen, um das Ausführen von beliebigem Code über ein Template zu erlauben. (Zum Beispiel in dem man eine class Evil { public function evil($code) { eval($code); } } erstellt.)
Ich würde die Smarty Entwickler und auch den lord nicht als dumm bezeichnen.
Die haben sicherlich schon was aufm Kasten.
Außerdem parst du doch den Template Code der mit PHP versetzt wurde. Ob jetzt mit "eval ()" o.ä. ist ja egal.
Da reicht eine Abfrage zu wenig und du hast nen Problem.
Die Effizienz bei der Erstellung von diesem ist unbedeutend. Der Code wird gecacht, d.h. es wird ein mal langsam kompiliert, danach ist das Template immer in kompiliertem Zustand griffbereit. Bei seriösen Projekten sind zusätzlich sogar OPCODEs des Templates im Arbeitsspeicher, da seriöse Leute bekanntlich APC nutzen ;)
Seriös.... :P
BIsher habe ich eigentlich nur Memcached genutzt. Bei PHP Code hatte ich eigentlich noch keine großen Geschwindigkeitsprobleme.
Also an sich ist die Erstellung langsam, aber wenn man das Produkt daraus cacht, wird es flotter, als meine Idee.
Jetzt ist bloß die Frage, was passiert, wenn man für meine Idee einen Cache nutzt? :P
Ist wahrscheinlich eher schwierig die Logik bei mir zu cachen. Höchstens die komplette Ausgabe der angeforderten Website.
Beitrag zuletzt geändert: 4.8.2010 11:48:01 von lucas9991 -
lucas9991 schrieb:
Ich finde unsinnig, weil es in meinen Augen ein Widerspruch ist.
Auf der eine Seite sagst du, du würdest PHP und HTML Code trennen. Auf der anderen Seite erfolgt diese Trennung aber nur indirekt durch eine weitere Abstraktionsschicht (dem Pseudo Code).
Heh. Wir drehen uns irgendwie im Kreis... es wird Zeit etwas Code ins Spiel zu bringen. Das typische Blogbeispiel.
Mit Twig:
controllers/blog.php <?php class BlogController extends Controller { public static function index() { $this->loadTpl('blog.html'); $this->tpl->posts = $this->db->get('posts', 5); // get 5 last posts } } templates/blog.html {% for post in posts %} <h1>{{ post.title }}</h1> <p>{{ post.body }}</p> <hr> {% else %} <p>Noch keine Blogeinträge :(</p> {% endfor %}
So stelle ich es mir bei dir vor (bis auf Model -> Controller):
controllers/blog.php <?php class BlogController extends Controller { public static function index() { $this->loadTpl('blog.html'); $posts = $this->db->get('posts', 5); // get 5 last posts if (!$posts) { $this->tpl->posts = '<p>Leider noch keine Posts :(</p>'; } $this->tpl->posts = ''; foreach ($posts as $post) { $body = nl2br($post->body); $this->tpl->posts .= <<<EOC <h1>{$post->title}</h1> <p>{$body}</p> <hr> EOC; } } } templates/blog.html {{ posts }}
So, jetzt der Grund, warum ich ersteres bevorzuge. Stellen wir uns mal vor wir sind ein kleines Team, ein Programmierer, ein Designer. Der Designer hat nicht sonderlich viel Ahnung von PHP (und der Programmierer mag es gar nicht, wenn jemand anders an seinem Code herumpfuscht) und der Programmierer ist nicht der geborene Grafiker. Jeder macht einfach sein Ding.
Nun, stellen wir uns vor der Designer ist ein guter und er steigt auf die neuen HTML5 Sectioning Elements um. Was müsste er bei "meinem" Fall tun? Die blog.html bearbeiten, ein paar Tags ändern, sonst nichts. Was müsste er in "deinem" Fall tun? Entweder deinen Code anpassen (mit der Gefahr Scheiße zu bauen) oder dir sagen, dass du deinen Code ändern sollst. Nicht gut.
So, und jetzt sag mir bitte: Was genau findest du an dem Code mit Twig jetzt schlecht, ineffektiv, sonstiges? Bitte komm mir jetzt nicht wieder mit irgendwelchen Programmiererparadigmen "Man soll Logik und View trennen". Das interessiert mich nicht. Mich interessiert, was effektiver ist (Arbeitszeit verkürzt und Arbeit im Team erleichtert.)
Da scheiden sich häufig die Geister. Bei PHP Anwendungen finde ich es so allerdings nützlich, da die eigentliche Daten in der Regel in Datenbanken liegen.
Ja, Datenbank ist Model. Warum sollte man da nun Logik reinpacken?
Blöcke sind per se keine if-Abfragen. Es sind einfach nur extra ausgezeichnete Textabschnitte.
Extra ausgezeichnet, damit sie ausgelesen werden können und manipuliert werden können.
Wie sie manipuliert werden kann man in der View aber nicht erkennen, das hängt ganz vom Model (oder Controller bei dir ) ab.
Verstehe ich nicht recht. Da sie aber offensichtlich (wenn auch nur gerinste) Logik haben, können sie im Template doch nichts zu suchen haben ;)
HTML Code ist nicht im Model.
Naja, so wie du es darstellst schon. Du brauchst ja ne Schleife für die Ausgabe der Blogeinträge und die HTML-Tags müssen da ja irgendwie drin sein. Und wenn die Schleife bei dir nicht im View ist, sondern im Model...
Nun, ich nicht. Man müsste sich als Entwickler schon äußerst dumm anstellen, um das Ausführen von beliebigem Code über ein Template zu erlauben. (Zum Beispiel in dem man eine class Evil { public function evil($code) { eval($code); } } erstellt.)
Ich würde die Smarty Entwickler und auch den lord nicht als dumm bezeichnen.
Huh? Ich hab in dem Absatz weder etwas über Smarty noch etwas über den Lord geschrieben... Das was ich da geschrieben habe bezieht sich sogar eher auf Twig. Man würde Ausführung von belibigem Code erlauben, wenn man so eine Klasse erstellt und eine Instanz von ihr an Twig übergibt. Dann könnte man mit {{ $evil->evil('`rm -rf /`') }} beliebigen Coed ausführen. Aber um das zu machen muss man schon mächtig unterbelichtet sein.
Außerdem parst du doch den Template Code der mit PHP versetzt wurde. Ob jetzt mit "eval ()" o.ä. ist ja egal.
Da reicht eine Abfrage zu wenig und du hast nen Problem.
Du siehst dir bitte ein kompiliertes Twig-Template an und sagst mir, wo du da potentielle Schwachstellen siehst, bevor wir diesen Teil der Diskussion fortführen.
Die Effizienz bei der Erstellung von diesem ist unbedeutend. Der Code wird gecacht, d.h. es wird ein mal langsam kompiliert, danach ist das Template immer in kompiliertem Zustand griffbereit. Bei seriösen Projekten sind zusätzlich sogar OPCODEs des Templates im Arbeitsspeicher, da seriöse Leute bekanntlich APC nutzen ;)
Seriös.... :P
War auch net ganz ernst gemeint ;) Aber ehrlich, jedes größere Projekt nutzt einen Opcode Cache. Ob es nun APC ist, XCache oder eAccelerator - irgendeiner wirds sein.
BIsher habe ich eigentlich nur Memcached genutzt. Bei PHP Code hatte ich eigentlich noch keine großen Geschwindigkeitsprobleme.
Memcached cacht leider keine Opcodes ;)
Also an sich ist die Erstellung langsam, aber wenn man das Produkt daraus cacht, wird es flotter, als meine Idee.
Jetzt ist bloß die Frage, was passiert, wenn man für meine Idee einen Cache nutzt? :P
Naja, was willst du bei deiner Idee nochmal cachen? Den Syntaxtree? Auch wenn er gecacht ist, auch wenn er sogar im Arbeitsspeicher ist in einem handlichen Format, musst du ihn dennoch zur Laufzeit durchgehen. Gesteh es dir ein: PHP-Code ist einfach das schnellste, was du unter PHP bekommst ... da geht nichts noch schnellers, das wäre paradox.
Beitrag zuletzt geändert: 4.8.2010 13:30:36 von nikic -
nikic schrieb:
So stelle ich es mir bei dir vor (bis auf Model -> Controller):
controllers/blog.php <?php class BlogController extends Controller { public static function index() { $this->loadTpl('blog.html'); $posts = $this->db->get('posts', 5); // get 5 last posts if (!$posts) { $this->tpl->posts = '<p>Leider noch keine Posts :(</p>'; } $this->tpl->posts = ''; foreach ($posts as $post) { $body = nl2br($post->body); $this->tpl->posts .= <<<EOC <h1>{$post->title}</h1> <p>{$body}</p> <hr> EOC; } } } templates/blog.html {{ posts }}
Du hast mich leider immer noch nicht verstanden. ^^
In der Template Datei werden die Blöcke gekennzeichnet. in all meinen PHP Dateien steht kein HTML Code und auch kein Plain Text, der an den Benutzer gesendet wird.
Beispiel:
Template: <html> ... [posts] <div> <h1>{posts_title}</h1> <div> {posts_text} </div> </div> [/posts] ... </html> --------- Model <?php class BlogModel extends Model { public function index($pParam = array()) { $data = ....; // mehrdimensionales Array mit Posts array (0 => array ('post_title' => 'Erster Eintrag', 'posts_text' => 'Text')) $View -> loadFile ('template.tpl'); // lese Template ein (und speichere es zwischen) $View -> loadBlock ('template.tpl', 'posts'); // lese Block aus Template ein (und speichere es zwischen) foreach ($data as $index => $array) { $View -> enlargeBlock ('posts', $array); // nehme den Block "posts" und ersetze in diesem die Platzhalter durch die Indexe aus dem Array $data[0] } return ($View -> getView('template.tpl')); // ersetze "[posts](.*)[/posts]" mit dem Inhalt der durch "enlargeBlock" erzeugt wurde }
So, jetzt der Grund, warum ich ersteres bevorzuge. Stellen wir uns mal vor wir sind ein kleines Team, ein Programmierer, ein Designer. Der Designer hat nicht sonderlich viel Ahnung von PHP (und der Programmierer mag es gar nicht, wenn jemand anders an seinem Code herumpfuscht) und der Programmierer ist nicht der geborene Grafiker. Jeder macht einfach sein Ding.
Nun, stellen wir uns vor der Designer ist ein guter und er steigt auf die neuen HTML5 Sectioning Elements um. Was müsste er bei "meinem" Fall tun? Die blog.html bearbeiten, ein paar Tags ändern, sonst nichts. Was müsste er in "deinem" Fall tun? Entweder deinen Code anpassen (mit der Gefahr Scheiße zu bauen) oder dir sagen, dass du deinen Code ändern sollst. Nicht gut.
Das Logik und View getrennt werden sollte, ist klar. Darum ging es mir nie.
So, und jetzt sag mir bitte: Was genau findest du an dem Code mit Twig jetzt schlecht, ineffektiv, sonstiges? Bitte komm mir jetzt nicht wieder mit irgendwelchen Programmiererparadigmen "Man soll Logik und View trennen". Das interessiert mich nicht. Mich interessiert, was effektiver ist (Arbeitszeit verkürzt und Arbeit im Team erleichtert.)
Arbeitszeit: vermag ich nicht eizuschätzen
Erleichterung der Teamarbeit:
Es beugt Problemen und Unerwartetem Verhalten vor. Wenn der Designer keine Möglichkeit hat Logik zu implementieren, kann er auch nichts falsch machen.
Ja, Datenbank ist Model. Warum sollte man da nun Logik reinpacken?
Keine Ahnung, wer sagt so etwas?
Blöcke sind per se keine if-Abfragen. Es sind einfach nur extra ausgezeichnete Textabschnitte.
Extra ausgezeichnet, damit sie ausgelesen werden können und manipuliert werden können.
Wie sie manipuliert werden kann man in der View aber nicht erkennen, das hängt ganz vom Model (oder Controller bei dir ) ab.
Verstehe ich nicht recht. Da sie aber offensichtlich (wenn auch nur gerinste) Logik haben, können sie im Template doch nichts zu suchen haben ;)
Sie haben eben _keine_ Logik. Es mögen logische Auszeichnungen seien, aber die Ähnlichkeit des Namens macht es trotzdem nicht zur Logik.
Naja, so wie du es darstellst schon. Du brauchst ja ne Schleife für die Ausgabe der Blogeinträge und die HTML-Tags müssen da ja irgendwie drin sein. Und wenn die Schleife bei dir nicht im View ist, sondern im Model....
Die Schleife ist im Model, aber der HTML Code steht trotzdem in der View.
Genau um diese Trennung geht es mir ja.
Huh? Ich hab in dem Absatz weder etwas über Smarty noch etwas über den Lord geschrieben... Das was ich da geschrieben habe bezieht sich sogar eher auf Twig. Man würde Ausführung von belibigem Code erlauben, wenn man so eine Klasse erstellt und eine Instanz von ihr an Twig übergibt. Dann könnte man mit {{ $evil->evil('`rm -rf /`') }} beliebigen Coed ausführen. Aber um das zu machen muss man schon mächtig unterbelichtet sein.
Soweit ich mich erinnere gab es in Smarty zur Anfangszeit eine "eval ()" Lücke über die man beliegen Code ausführen konnte und auch bei lima gab es solch eine Lücke.
Und die Entwickler beider Sachen würde ich trotzdem nicht als unterbelichtet ansehen.
Du siehst dir bitte ein kompiliertes Twig-Template an und sagst mir, wo du da potentielle Schwachstellen siehst, bevor wir diesen Teil der Diskussion fortführen.
Habe ich leider keines gefunden zur eigenen Erstellung habe ich leider im Moment nicht die Zeit.
Also an sich ist die Erstellung langsam, aber wenn man das Produkt daraus cacht, wird es flotter, als meine Idee.
Jetzt ist bloß die Frage, was passiert, wenn man für meine Idee einen Cache nutzt? :P
Naja, was willst du bei deiner Idee nochmal cachen? Den Syntaxtree? Auch wenn er gecacht ist, auch wenn er sogar im Arbeitsspeicher ist in einem handlichen Format, musst du ihn dennoch zur Laufzeit durchgehen. Gesteh es dir ein: PHP-Code ist einfach das schnellste, was du unter PHP bekommst ... da geht nichts noch schnellers, das wäre paradox.
Twig speichert den aus einem Template erzeugten PHP Code zwischen. Die Ausgabe bei einem Aufruf ist immer aktuell.
Ich würde den generierten HTML Code zwischenspeichern. Dieser wäre nicht bei jedem Aufruf aktuell, würde aber nach einem festgelegten Intervall aktualisiert werden.
Und HTML Code ist schneller als PHP Code.
Allerdings ist das jetzt nur sehr einseitig betrachtet. -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage