{"id":390,"date":"2009-09-10T18:11:04","date_gmt":"2009-09-10T16:11:04","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=390"},"modified":"2009-09-18T21:29:27","modified_gmt":"2009-09-18T19:29:27","slug":"templating-in-1000-lines-of-code","status":"publish","type":"post","link":"https:\/\/blog.benny-baumann.de\/?p=390","title":{"rendered":"Templating in 1000 Lines of Code"},"content":{"rendered":"<p>Ich wei\u00df, es gibt bereits viele Templater, aber die meisten scheitern entweder an einfachsten Aufgaben, oder sind zu \u00fcberdimensioniert oder anderweitig zu Speziell f\u00fcr bestimmte Anforderungen. Daher mein Einwurf f\u00fcr die Diskussion um einen Templater: das Projekt 1kLOC Templater ist ein Versuch, einen flexiblen, performanten, aber gleichzeitig kleinen Templater zu schreiben.<!--more--><\/p>\n<p>Das Projekt ist dabei mehr oder weniger ein Test gewesen, ob es m\u00f6glich ist, entwickelte sich aber recht schnell zu einer Art kleinen Wettbewerb, wie klein man solch einen Templater bekommt. Aber vielleicht fange ich am besten einmal bei der Vorgeschichte an, da noch ein weiteres Template-System ja an sich nichts Besonderes ist.<\/p>\n<h2>Andere Template-Systeme<\/h2>\n<p>Meine Arbeit mit verschiedenen Template-Systemen fing etwa 2002 mit dem im phpBB enthaltenen Templater an. Damals bestand mein Kontakt mit diesen Systemen im Wesentlichen aus dem Anpassen der Templates, was gerade beim phpBB eine recht einfache und \u00fcbersichtliche Aufgabe ist, in der sich auch ein Einsteiger recht einfach zurechtfindet. Da ich irgendwann vom reinen phpBB auf Grund der Vielzahl an einzubauenden Mods irgendwann zum phpBB Plus bzw. CBack Orion gewechselt bin, wechselte sich auch das Templatesystem mit dem ich Hauptkontakt hatte zum Xtreme Styles Mod, der im CBack-Forum eingebaut war. Dieser bot gegen\u00fcber dem Standard-Templater des phpBB eine Reihe von Vorteile, wie z.B. das nutzen von PHP-Code direkt im Template oder ein verbessertes Schleifenhandling, was jedoch mit einfachsten Template-Fehlern aus dem Tritt zu bringen war. So gen\u00fcgte es oftmals bereits, in einem Schleifenkopf auf den falschen Kontext zuzugreifen (also foo.bar statt nur bar, wenn foo bereits eine Schleife war), um Syntax-Fehler im Template-Cache zu provozieren.<\/p>\n<p>Sp\u00e4ter kam ich auch kurz mit Smarty in Ber\u00fchrung, hielt es aber auf Grund seiner Gr\u00f6\u00dfe f\u00fcr keine sinnvolle Alternative zu den im phpBB verwendeten Templatern &#8211; Smarty ist einfach extrem aufgebl\u00e4ht, auch wenn hier das erste Mal richtige If-Anweisungen verf\u00fcgbar waren, die im phpBB und Xtreme Styles Mod immer umst\u00e4ndlich \u00fcber Switches\\Schleifen realisiert werden mussten. Dies war zwar ein gewaltiger Fortschritt rechtfertigt aber bei weitem nicht, einen Templater mit \u00fcber 3 MB Source zu haben: der Xtreme Styles Mod ist etwa 70 kB gro\u00df und beherrscht Styling, d.h. verschiedene Template-Pfade pro Template.<\/p>\n<p>Sp\u00e4ter stie\u00df ich auch auf Dwoo, was mehr oder ein Rewrite von Smarty ist. Also mit all seinen Nachteilen. So erlauben sowohl Dwoo wie auch Smarty das direkte Ausgeben der Request-Parameter in einem Template &#8211; eine Funktion, die aus Sicherheitsaspekten ein Alptraum ist, da sie gerade unerfahrenen Nutzern die M\u00f6glichkeit bietet, sich XSS-L\u00fccken einzuhandeln, ohne es zu merken. Wieder ein Punkt, was im Xtreme Styles Mod intelligenter gel\u00f6st war: Hier musste man jede zu nutzende Variable explizit ins Template importieren, was zwar in Schreibarbeit ausarten konnte, aber einem sofort bewusst gemacht hat, dass man sich um die auszugebenden Daten k\u00fcmmern muss. Dies hat zwar auch das unbedachte Erzeugen von XSS-L\u00fccken ausgeschlossen, hat jedoch zumindest das Bewusstsein f\u00fcr die auszugebenden Daten gesch\u00e4rft.<\/p>\n<p>Zwischenzeitlich bin ich bei ViewVC (Python) auch mit deren Template-System in Ber\u00fchrung gekommen, was im Grunde zwar an Smarty angelehnt ist, jedoch eine noch kryptischere Syntax aufweist, als Smarty ohnehin schon.<\/p>\n<p>Wenn man diverse PHP-Anwendungen warten und ggf. sogar umprogrammieren muss, kommt man nicht zuletzt auch einmal an der &#8211; f\u00fcr mich bisher schlimmsten &#8211; Form von Templating vorbei, die gegen\u00fcber dem Umstand, weshalb man eigentlich Templating nutzt nahezu nichts \u00e4ndert: PHP Templates. Eine Mischung aus Wir w\u00f6llten gern und k\u00f6nnens aber nicht. Diese Abart von Templates kommt bevorzugt in CMS (Code Mangling Systems) zum Einsatz &#8211; also gerade da, wo das System eh schon komplex genug ist, als dass man erwarten k\u00f6nnte, wenigstens das Bearbeiten des Seitenstils stark zu vereinfachen.<\/p>\n<h2>Anforderungen an meinen Templater<\/h2>\n<p>Nun m\u00f6chte ich in absehbarer Zeit ein Projekt anfertigen, bei dem ich auf recht alter Hardware arbeiten muss, womit bei meiner Wahl Schwergewichte wie Smarty und Dwoo von vornherin ausfallen. Abarten wie PHP-Templates nat\u00fcrlich auch, da Templates zum Steigern der \u00dcbersichtlichkeit gedacht sind. Und obwohl ich die beiden Template-Systeme f\u00fcr&#8217;s phpBB eigentlich recht gut mag, fallen diese auf Grund ihrer starken Integration ins phpBB f\u00fcr meine Zwecke auch flach, obwohl ich auf diesen aufbauend bereits ein anderes Projekt gebaut habe, was bisher mehr als zufriedenstellend l\u00e4uft.<\/p>\n<p>Da somit jegliche Templatesysteme mehr oder weniger ausgeschlossen sind, stellte sich die Frage, ob es eine eigenentwicklung werden sollte: Nach mehr oder weniger kurzem \u00dcberlegen stand die Antwort &#8222;Ja&#8220; fest, da basierend auf den Erfahrungen mit GeSHi das Schreiben eines vern\u00fcnftigen und vor allem schnellen Parsers kein Problem darstellen sollte.<\/p>\n<p>Und so entstanden auch die Rahmenbedingungen und Anforderungenf\u00fcr den Templater: M\u00f6glichst klein &#8211; 1kLOC klang hier als eine durchaus machbare Grenze, die dennoch eine Herausforderung darstellt -, eine dem phpBB-Parser \u00e4hnliche Syntax &#8211; auch wenn hier {$&#8230;} f\u00fcr Variablen ein wenig abweicht -, und m\u00f6glichst einfach erweiterbar.<\/p>\n<p>Ferner sollte der Templater Styling unters\u00fctzen, verschiedene Ablageorte f\u00fcr Templates erm\u00f6glichen, Cachen k\u00f6nnen und KEIN eval beinhalten. Auch strikt untersagt war nat\u00fcrlich der Evil-Modifier, zu dem ich ja bereits an anderer Stelle etwas geschrieben hatte.<\/p>\n<p>Eine weitere Grundlage f\u00fcr das Design war die Nutzung von PHP5 und seiner M\u00f6glichkeiten. Dies hie\u00df nicht nur, dass Klassen zum Einsatz kommen sollten, sondern mit den Klassen auch Code-Reduktion und Redundanz-Vermeidung zu betreiben war &#8211; mehr oder weniger durch die begrenzte Anzahl verf\u00fcrbarer Code-Zeilen ;-).<\/p>\n<h2>Funktionsweise des Systems<\/h2>\n<p>Was nun gegen\u00fcber den vorab erw\u00e4hnten Templatern neu ist, ist die M\u00f6glichkeit von Subtemplating, d.h. Rendern von Templates, die aus anderen Templates zusammengesetzt werden. der phpBB-Templater l\u00f6ste diese Aufgabe mit verschiedenen Template-Handles, die man dann zwischen den Templates kopiert hat. Dies war nicht nur aufw\u00e4ndig zu programmieren, sondern war auch sehr unflexibel, da es f\u00fcr h\u00e4ufig vorkommende Boxen, in denen weitere Elemente zu platzieren sind immer eigenen Code zum Rendern dieser Elemente ben\u00f6tigte. Hier sollte mein Templater von vornherein eine effizientere L\u00f6sung anbieten, die auch ohne Code auf der Seite der Anwendung diese doch recht h\u00e4ufig anzutreffende Form der Style-Nutzung erm\u00f6glicht: Halt Subtemplating durch Anweisungen im Template.<\/p>\n<p>Dieses Feature wird dabei, \u00e4hnlich wie andere Erweiterungsfunktionen durch eine Markierung im Template aktiviert:<\/p>\n<pre lang=\"html4strict\" escaped=\"true\">&lt;!--#TPL name=\"sub.tpl\"#--&gt;\r\n&lt;!--#TPLParam name=\"param1\"#--&gt;Hallo Welt!&lt;!--#\/TPLParam#--&gt;\r\n&lt;!--#\/TPL#--&gt;<\/pre>\n<p>Hierbei gibt der TPL-Tag an, dass ein weiteres Template einzubinden ist. Um dieses nun an den aufrufenden Kontext anzupassen, k\u00f6nnen eine Reihe von TPLParams (Template Parameter) \u00fcbergeben werden. Diese werden in diesem Subtemplate als ganz normale Variablen eingeblendet, so dass es f\u00fcr ein Template keinen Unterschied macht, wo es in einer Seite aufgerufen wird. Bei diesem Einblenden \u00fcberschreiben die TPLParams aus dem Elternkontext geerbte Variablen, um auch das Verschachteln von Templates zu erm\u00f6glichen.<\/p>\n<p>In diesem Zusammenhang ist dabei auch das Variablenhandling des 1kLOC-Templaters interessant. W\u00e4hrend andere Systeme im Wesentlichen Strings verarbeiten bietet der 1kLOC-Templater explizit die M\u00f6glichkeit auch ganze Objekte in den Variablen-Baum einzupflegen und damit die Daten virtuell in den Template-Kontext einzubinden. Auf diese Art wird es m\u00f6glich, dass man ein User-Objekt, dessen Daten eh bereits vorhanden sind, einfach \u00fcber eine kurze Schnittstelle an das System anbinden muss und somit der Templater die Daten live aus dem Objekt liest, statt dass diese explizit kopiert werden m\u00fcssen &#8211; das Escaping der Daten muss dabei bei der Anbindung der Schnittstelle gemacht werden, was jedoch kein gro\u00dfes Problem darstellt.<\/p>\n<p>Als Parser kommt wie bereits erw\u00e4hnt das Wissen aus der Programmierung am GeSHi zum Einsatz. Um das Template m\u00f6glichst schnell verarbeiten zu k\u00f6nnen wird hierbei \u00e4hnlich wie dies auch im GeSHi v1.0.X realisiert ist, nach dem fr\u00fchsten m\u00f6glichen Kontextwechsel gesucht, Text bis dorthin als Text-Knoten interpretiert und der gefundene Subkontext weiterverarbeitet. Dieses Parsing passiert hierbei unter Nutzung von Callback-Funktionen, was die einfache Weiterverwendung im Template Compiler erm\u00f6glicht, der die linear vom Parser erhaltenen Tokens in einen PArsing Tree konveriteren kann und anschlie\u00dfend aus diesem Baum den Cache-Source erstellen kann. Erstmals kam diese Art des Parsings im GeSHI jedoch nicht bei 1.0.X zum Einsatz, sondern wurde mehr oder weniger aus GeSHi 1.1.X gebackported, wobei dort noch eine Reihe anderer Faktoren eine wesentliche Rolle spielen und somit das Parsing ein wenig aufw\u00e4ndiger als beim nahezu ausgereizten GeSHi 1.0.X ist.<\/p>\n<p>Die Struktur vom 1kLOC Templater ist hierbei relativ einfach, aber dennoch sehr flexibel. Zentrale Aufrufstelle ist hierbei die TTemplater-Klasse. Diese stellt keine zwar keine Wesentliche Logik bereit, vereinfacht aber das Erzeugen von TEmplate-Objekten, ohne dass hierf\u00fcr jedes Mal alle Referenzen f\u00fcr die anderen verwendeten Klassen \u00fcbergeben werden m\u00fcssen. Mit der \u00fcber LoadTemplate erreichbaren Klasse TTemplate erh\u00e4lt man nun die Repr\u00e4sentation aller zu einem Tempalte geh\u00f6rigen Datenst\u00e4nde, d.h. dem Styler, dem Cache, dem Compiler sowie einem Variablen-Kontext, der die im Template verwendbaren Variablen beinhaltet.<\/p>\n<p>Der Styler wiederum k\u00fcmmert sich um das Lesen von Rohdaten f\u00fcr ein Template. Diesem wird vom Rest des Tempalte-Systems nur der Name des Tempaltes \u00fcbergeben. Weitere Angaben wie Verzeichnisse, Datenbank-Verbindungen und dergleichen sind von der Implementation dieses Stylers abh\u00e4ngig, was es erm\u00f6glicht, sowohl Templates aus dem Dateisystem des Servers, aber auch wie z.B. bei phpKit der Fall aus der Datenbank zu lesen. Um ein Mapping dieser Templaterohdaten auf den Cache zu erm\u00f6glichen, muss jeder Styler f\u00fcr ein Template eine eindeutige ID liefern k\u00f6nnen. Diese wird im weiteren Verlauf der Verarbeitung als GUID f\u00fcr dieses Tempalte genutzt und dient je nach Cache sp\u00e4ter auch zum Ablegen und wiederfinden der compilierten Daten.<\/p>\n<p>Der n\u00e4chste Schritt beim Rendern eines Templates, nach dem dieses vom Styler gelesen wurde ist das Compilieren. Hierzu wird die Compiler-Klasse aufgerufen, der ein Parser vorgeschalten wird. Der Parser wird hierbei wenn n\u00f6tig intern erzeugt, kann aber auch extern ausgetauscht werden. Dies erm\u00f6glicht die Wiederverwendung des Compilers, auch wenn sich das Layout bzw. die Art der Template-Speicherung ge\u00e4ndert hat. Einzig die Art, wie der Parser die Tokens liefert muss mit dem Format und der Schnittstelle des Compilers kompatibel sein, um einen Austausch zu erm\u00f6glichen.<\/p>\n<p>Nach dem der Compiler aus dem Template-Source eine Cache-f\u00e4hige Version erzeugt hat, was sowohl PHP-Source (default) aber auch vollkommen andere Informationen wie Bytecode sein k\u00f6nnten, wird der Cache damit beauftragt, diese Informationen zwischenzuspeichern, um die recht aufwendige Arbeit des Compilierens wann immer m\u00f6glich einzusparen.<\/p>\n<p>Der Compiler ist beim 1kLOC-Templater neben der Umsetzung in Code auch mit dessen Ausf\u00fchrung besch\u00e4ftigt, da er als einziger die genaue Art und Weise zu dessen Ausf\u00fchrung kennt. Somit ist im Endeffekt nicht mal festgelegt, wie ein compiliertes Template aussehen muss, was insbesondere dann Vorteile bietet, wenn durch zus\u00e4tzliche Extensions effizientere Ausgabem\u00f6glichkeiten entstehen die Ausf\u00fchrung wesentlich beschleunigt werden kann, ohne den Templater an sich \u00fcber den Haufen werfen zu m\u00fcssen.<\/p>\n<h2>Nutzung des 1kLOC Templaters<\/h2>\n<p>Wer bereits einmal Erfahrungen mit den Templatern f\u00fcr phpBB gesammelt hat, d\u00fcrfte mit der Nutzung meines Templaters nahezu keine Probleme haben, da die Nutzung sehr intuitiv gestaltet ist. Meine Demo-Seite besteht mit den beiden genutzten Templates aus lediglich folgenden Codezeilen:<\/p>\n<pre lang=\"php\" escaped=\"true\">&lt;?php\r\ninclude dirname(__FILE__).'\/TTemplater.php';\r\n\r\n$tpl = new TTemplater();\r\n\r\n$main = $tpl-&gt;LoadTemplate('main.tpl');\r\n$main-&gt;assignVar('foo', 42);\r\n$main-&gt;assignBlock('bar', array('a'=&gt;1, 'b'=&gt;2, 'c'=&gt;3));\r\n$main-&gt;assignBlock('bar', array('a'=&gt;4, 'b'=&gt;5, 'c'=&gt;6));\r\n$main-&gt;assignBlock('bar', array('a'=&gt;7, 'b'=&gt;8, 'c'=&gt;9));\r\n$main-&gt;render();\r\n?&gt;<\/pre>\n<p>Die Templates sind dabei auch recht einfach aufgebaut. Da man ein HTML-Grundger\u00fcst h\u00e4ufig ben\u00f6tigt, ist dieses als Subtemplate realisiert:<\/p>\n<pre lang=\"html4strict\" escaped=\"true\">&lt;html&gt;\r\n&lt;head&gt;\r\n&lt;title&gt;{$title}&lt;\/title&gt;\r\n&lt;\/head&gt;\r\n&lt;body bgcolor=\"#ffeecc\"&gt;\r\n&lt;h1&gt;It Works!&lt;\/h1&gt;\r\n{$content}\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<p>Die eigentliche Seite ist in main.tpl realisiert und fordert darin an, in dieses Grundger\u00fcst eingesetzt zu werden:<\/p>\n<pre lang=\"html4strict\" escaped=\"true\">&lt;!--#TPL name=\"structure.tpl\"#--&gt;\r\n&lt;!--#TPLParam name=\"title\"#--&gt;Hallo Welt!&lt;!--#\/TPLParam#--&gt;\r\n&lt;!--#TPLParam name=\"content\"#--&gt;\r\nThe answer is {$foo}.&lt;br \/&gt;\r\n&lt;!--#If isset=\"foo\" #--&gt;\r\n&lt;b>Told you so!&lt;\/b>&lt;br \/&gt;\r\n&lt;!--#\/If#--&gt;\r\n&lt;br \/&gt;\r\n&lt;!--#For name=\"bar\" #--&gt;\r\nA:{$bar:a}, B:{$bar:b}, C:{$bar:c}&lt;br \/&gt;\r\n&lt;!--#\/For#--&gt;\r\n&lt;!--#\/TPLParam#--&gt;\r\n&lt;!--#\/TPL#--&gt;<\/pre>\n<p>Hierbei ist es m\u00f6glich, nicht nur Skalare an assignVar zu \u00fcbergeben, sondern sogar Objekte, sofern diese die __toString-Methode von PHP implementieren, um eine String-Repr\u00e4sentation von sich selbst zu erzeugen. Dies ist f\u00fcr die TTemplate-Klasse durch einen internen Aufruf der render()-Methode und der R\u00fcckgabe der erzeugten Ausgabe realisiert. Diese Funktion kann aber durch zus\u00e4tzliche Implementierung des ITPLContext-Interfaces noch erweitert werden, da dann das Template-System auch Anfragen an Unterkontexte erlaubt, d.h. das Objekt wie im Template-Kontext gespeicherte Daten behandelt und Aufrufe entsprechend weiterleitet. Somit l\u00e4sst sich \u00fcber einen minimalen Wrapper jedes Objekt direkt im Template-System nutzen ohne explizit jede einzelne Eigenschaft kopieren zu m\u00fcssen.<\/p>\n<p>Die Datenhaltung erfolgt aus Sicht des Template-Systems immer \u00fcber Arrays, denen ein Name zugeordnet ist. Hierbei ist jeder Teilname durch einen Doppelpunkt getrennt (XML-Syntax). Die Auswertung der Namen erfolgt dabei von links nach rechts, wobei als R\u00fcckgabe eines Namens immer dessen aktueller Index zur\u00fcckgeliefert wird. Das mehrfache setzen eines Wertes erg\u00e4nzt weitere Werte zu diesem Namen. Diese Eigenschaft kann insbesondere f\u00fcr Schleifen genutzt werden, da sich somit recht einfach umfangreiche Datenstrukturen erzeugen lassen.<\/p>\n<p>M\u00f6chte man nun neben den im Grundsystem enthaltenen Tags f\u00fcr If&#8230;Then&#8230;ElseIf&#8230;Else, For (ForElse kommt ggf. demn\u00e4chst noch) sowie Subtemplating mehr haben, so kann man dies ganz einfach nachr\u00fcsten, indem man von der TTemplateCompiler_Tag-Klasse, bzw. f\u00fcr Bl\u00f6cke von TTemplateCompiler_Block ableitet und den Tagnamen an diesen Grundnamen anh\u00e4ngt und die statische getCode-Methode implementiert. Die Code-Erzeugung l\u00e4uft dabei \u00fcber eine Callback-Funktion, der der zu erzeugende Code \u00fcbergeben wird. Im erzeugten Code gibt es nun 5 Variablen von Bedeutung:<\/p>\n<ol>\n<li>$this = Der Compiler<\/li>\n<li>$tpl = Das Tempalte-Objekt, das gerendert wird<\/li>\n<li>$context = Der aktuelle Variablen-Kontext<\/li>\n<li>$subcontext = Tempor\u00e4re Variable zum Erzeugen von Sukontexten<\/li>\n<li>$out = Callback f\u00fcr Datenausgabe<\/li>\n<\/ol>\n<p>Diese Vorgehensweise ist jedoch von Compiler zu Compiler abh\u00e4ngig, wird in dieser Form jedoch vom Standardcompiler umgesetzt. Dies ist insofern zu beachten, da im Template-System sogar der Compiler ausgetauscht werden kann, wenn er einem nicht gef\u00e4llt, oder es andere Gr\u00fcnde gibt, von der Standardimplementierung abzuweichen, um z.B. andere Tagformate zu unterst\u00fctzen oder Vorteile von Beschleuniger-Extensions besser ausnutzen zu k\u00f6nnen.<\/p>\n<h2>Jetzt will ich das Teil endlich haben &#8230;<\/h2>\n<p>Kein Problem: Der Templater steht unter GPLv3, kann aber unter Nennung guter Gr\u00fcnde und Leistung wirkungsvoller \u00dcberzeugungsarbeit in Einzelf\u00e4llen auch unter anderen Lizenzen bereitgestellt werden. \ud83d\ude09 Obwohl nicht zwingend notwendig, w\u00e4re zudem eine R\u00fcckmeldung \u00fcber Neuerungen, Verbesserungen an mich w\u00fcnschenswert, um Verbesserungen bereits Upstream einpflegen zu k\u00f6nnen. Den Download gibt&#8217;s <a href=http:\/\/blog.benny-baumann.de\/?attachment_id=401 rel='attachment wp-att-401'>&gt;&gt;&gt; hier &lt;&lt;&lt;<\/a>. Die Standard-Konfiguration geht von zwei Unterverzeichnissen cache\/ (Writeable) und tpl (Read-Only) aus, die bereits existieren m\u00fcssen. Ansonsten einfach einbinden und freuen!<\/p>\n<p>F\u00fcr R\u00fcckfragen steh ich gerne bereit.<\/p>\n<p>P.S.: Ja, ich wei\u00df, dass da noch 150 Zeilen Platz sind &#8230;<\/p>\n<p class=\"wp-flattr-button\"><a href=\"https:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=390&amp;md5=21f42811c82d199c4840fd93d9df593a\" title=\"Flattr\" target=\"_blank\"><img src=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" srcset=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" alt=\"Flattr this!\"\/><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Ich wei\u00df, es gibt bereits viele Templater, aber die meisten scheitern entweder an einfachsten Aufgaben, oder sind zu \u00fcberdimensioniert oder anderweitig zu Speziell f\u00fcr bestimmte Anforderungen. Daher mein Einwurf f\u00fcr die Diskussion um einen Templater: das Projekt 1kLOC Templater ist ein Versuch, einen flexiblen, performanten, aber gleichzeitig kleinen Templater zu schreiben.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[29],"tags":[98,234,345,21,232,77,233],"class_list":["post-390","post","type-post","status-publish","format-standard","hentry","category-software","tag-developement","tag-dwoo","tag-geshi","tag-php","tag-phpbb","tag-release","tag-smarty"],"_links":{"self":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/390","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=390"}],"version-history":[{"count":14,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/390\/revisions"}],"predecessor-version":[{"id":414,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/390\/revisions\/414"}],"wp:attachment":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=390"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=390"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=390"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}