Für Unsicherheit sorgte zunächst vor allem die Aussage, Smarty 3 sei nicht abwärtskompatibel zu Smarty 2. Die Entwickler haben sich um eine hohe Rückwärtskompatibilität bemüht, daher trifft das nur für einige (wenige) Punkte zu. In jedem Fall bietet die neue Smarty-Version jede Menge Verbesserungen und neue Features. Smarty 3 ist dabei nicht einfach eine Weiterentwicklung von Smarty 2, sondern wurde von Grund auf neu programmiert. Es ist nun komplett in PHP 5 geschrieben und der Parser/Compiler wurde um einen Lexer erweitert (Kasten: Lexer/Parser), mit dem verschiedene Syntaxverbesserungen, frühere Fehlererkennung, rekursive Funktionen und andere Features möglich werden. Die Smarty-Entwickler versprechen eine intuitivere Nutzung, schnelleres Einarbeiten und höhere Performance. Eine bestmögliche Abwärtskompatibilität stand dabei immer im Vordergrund – es sind kaum Effekte auf das öffentliche API gegenüber Smarty 2 zu bemerken.
Lexer/Parser
Ein Compilier-Vorgang besteht aus mehreren Phasen, zu denen auch die Lexikalische Analyse (Scanning) und die Syntaktische Analyse (Parsing) gehören. Der Lexer, auch Scanner genannt, zerlegt den Quellcode in seine einzelnen Bestandteile: Variablen, Operatoren und Symbole. Der Parser prüft diese einzelnen Bestandteile auf syntaktische Richtigkeit und ordnet sie zu hierarchischen Gruppen.
Das neueste Betarelease kann auf der offiziellen Smarty-Seite heruntergeladen werden. Man kann auch das SVN-Repository nutzen, auf dem die jeweils aktuellste Version zur Verfügung steht. Die Verzeichnisstruktur hat sich gegenüber der von Smarty 2 nur geringfügig geändert:
/
Smarty.class.php
/sysplugins/
internal.*
/plugins/
block.*
function.*
modifier.*
...
Das Verzeichnis /sysplugins enthält den Smarty Core. Die hier enthaltenen Dateien sollten Sie nicht verändern. In /plugins liegen die Plug-ins, mit denen die Funktionalitäten der Template Engine erweitert werden – wie auch schon bei Smarty 2. Hier können wie gewohnt eigene Plug-ins hinzugefügt werden. Anders als im Vorgänger sind Plug-ins in Smarty 3 Klassen, die Smarty_Internal_PluginBase erweitern. Jedes Plug-in hat die Eigenschaft $this->smarty, die eine Smarty-Instanz referenziert. Plug-ins im Smarty-2-Stil (Funktionen) werden weiterhin unterstützt, sie werden einfach ins /plugins-Verzeichnis von Smarty 3 übertragen.
Wie in Smarty 2 müssen auch die Verzeichnisse für Templates und Cache (/templates, /templates_c, /cache, /configs) selbst angelegt werden. /cache und /templates_c müssen Schreibrechte haben. Auch an der Einbindung der Smarty-Klasse in das Skript hat sich auf den ersten Blick nichts geändert:
require('Smarty.class.php');
$smarty = new Smarty();
$smarty->assign('foo','bar');
$smarty->display('index.tpl');
Objekte und Variablensichtbarkeit
In Smarty 2 werden alle zugewiesenen Variablen global in einem einzigen Smarty-Objekt gespeichert. Damit sind sie in sämtlichen Templates verfügbar. In Smarty 3 können Variablen ebenfalls dem Smarty-Objekt zugewiesen werden. Sie können aber auch einem Datenobjekt (Smarty_Data) oder einem Template-Objekt (Smarty_Template) übergeben werden. Damit wird es möglich, auf die Sichtbarkeit von Variablen Einfluss zu nehmen und so Namenskonflikte zu vermeiden. Das API von Daten- und Template-Objekten ähnelt der des Smarty-Objekts: Alle bekannten Methoden zum Zuweisen von Variablen können auch auf Daten- und Template-Objekte angewendet werden. Datenobjekte sind hier eine Art Variablencontainer mit eigenem Sichtbarkeitsbereich:
$data = new Smarty_Data();
$data->assign('foo','bar');
$data->load_conf('app.conf');
Datenobjekte können ein Smarty-Objekt oder ein anderes Datenobjekt als Elternklasse zugewiesen bekommen, indem die Objektinstanz dem Konstruktor als Parameter übergeben wird: $data = new Smarty_Data($smarty);. Jedes Template wird in Smarty 3 durch ein Objekt repräsentiert. Mittels Smarty_Template können einzelne Templates unabhängig gerendert werden, ohne das Singleton Pattern von Smarty zu verletzen. Um ein Template zu erzeugen, bedient man sich der createTemplate()-Methode des Smarty-Objekts. Diese Methode erwartet dann dieselben Parameter wie fetch() und display():
function createTemplate($template, $cache_id = null, $compile_id = null, $parent = null);
Der erste Parameter ist der Name des Templates. Es kann auch ein Smarty- oder ein Datenobjekt übergeben werden, dann wird eine Kopie dieses Objekts erzeugt. Der zweite Parameter ist die Elternklasse. Ein Template „erbt“ immer alle Variablen seiner Eltern, d. h. es hat auf diese Variablen Zugriff:
$tpl = $smarty->createTemplate('mytpl.tpl'); // ohne Elternklasse
$tpl = $smarty->createTemplate('mytpl.tpl',$smarty); // Smarty-Instanz ist Parent
$tpl->assign('foo','bar');
$tpl->conf_load('my.conf');
fetch() und display() erzeugen übrigens implizit ein Template-Objekt. Wird der vierte Parameter ($parent) dabei nicht spezifiziert, wird automatisch das Smarty-Objekt als Parent zugewiesen. Wird ein Template innerhalb eines anderen Templates via {include} aufgerufen, ist das aufrufende Template automatisch die Elternklasse des Subtemplates. Auf diese Weise können Template-Objekte beliebig tief miteinander verkettet werden. Das Objekt am Ende der Kette kann auf alle Variablen zugreifen, die zu diesem Template und zu den Elternobjekten gehören. Das Smarty-Objekt kann immer nur Wurzel einer solchen Kette sein, muss es aber nicht.
Jedes Template kann so auf seine eigenen Variablen und die seiner Eltern zugreifen. Variablen eines Subtemplates sind im Elterntemplate nicht verfügbar. Dasselbe gilt für Veränderungen, die im Subtemplate an Variablen des Elterntemplates vorgenommen wurden. Dieses Verhalten kennen wir bereits aus Smarty 2. In Smarty 3 kann Variablen zusätzlich ein Scope-Attribut zugewiesen werden. So ist es z. B. möglich, Variablen eines Subtemplates eine globale Sichtbarkeit zu geben, sodass diese auch im Elterntemplate verfügbar sind. Smarty kennt die Scopes local, parent, root und global:
{assign var=foo value='bar' scope='parent'}
{$foo='bar' scope='parent'} // Kurzform
local ist der Standardwert, die Variable ist nur lokal sichtbar. parent macht die Variable für das (direkte) Elterntemplate sichtbar, root macht sie für alle Templates der Objektkette sichtbar, also für sämtliche Elterntemplates bis zur Wurzel. Und mit scope='global' schließlich wird die Variable für alle Smarty-Templates der Anwendung verfügbar. Das Scope-Attribut kann auch dem {include}-Tag hinzugefügt werden, dann ist dieser Scope Standard für alle Variablen, die im inkludierten Template erzeugt oder verändert werden.



