Dziś jest sobota, 31 lipca 2010 roku (z kalendarza...)

Smarty 3

Icon

04.12.2009, 13:22

PHP

Komentarze (10)

Powrót

W ostatnich dniach witryna Smarty.net dosłownie zalewała nas kolejnymi wydaniami beta bilioteki Smarty 3, następcy systemu szablonów Smarty. Korzystając z chwili wolnego czasu, postanowiłem przyjrzeć mu się bliżej i ocenić, czy autorzy faktycznie czegoś się nauczyli przez ostatnie lata, bo - nie ukrywajmy - Smarty 2 to jeden z gorszych istniejących systemów szablonów, który żyje jedynie dzięki swej nieuzasadnionej popularności.

Interfejs biblioteki

Pierwsza zmiana, jaka rzuca się w oczy, to przejście na PHP5. Nowy Smarty nie zadziała na wersjach 4.x. Autorzy na razie nie potrafią określić, jakie będą minimalne wymagania dla PHP5, gdyż "piątka" przez pięć lat też nie próżnowała i PHP 5.3.0 to dużo bardziej rozbudowany produkt od PHP 5.0.0 wydanego w 2004 roku.

Na pierwszy rzut oka wygląda, że zmiana numerka i przejście na piątkę niewiele zmieniło w kwestii API biblioteki. Autorzy starali się zachować maksymalną kompatybilność wsteczną, dlatego w dalszym ciągu można pracować z systemem, posługując się jedynie "klasą do wszystkiego", co z ideą obiektowości ma niewiele wspólnego. Jednak oprócz tego, pojawiły się klasy Smarty_Data oraz Smarty_Template. Pierwsza z nich służy do definiowania zakresów widzialności, czyli zbiorów zmiennych, które używane są w szablonie. Nie jesteśmy już skazani na zmienne globalne, które przy bardziej zaawansowanych układach rodziły dużo problemów, niemniej wciąż można ich używać. Smarty_Template reprezentuje natomiast pojedynczy szablon, który podlega parsowaniu.

Wada projektu API ujawnia się, gdy zajrzymy do źródeł. Plik Smarty.class.php ma tylko 18 KB wielkości? Fajnie, lecz wszystko przez to, że główna klasa to w dużej mierze funkcja __call(), która w locie doładowuje potrzebne funkcje. Jeśli ktoś korzysta z aktywnego podpowiadania składni w edytorze, będzie klnąć na czym świat stoi, bo oczywiście przy takiej budowie edytor nie pokaże mu już ani dokumentacji, ani nawet faktu istnienia większości metod. Podstawowe metody, jak assign() czy assign_global() są ładowane z klasy bazowej Smarty_Internal_Data, tyle że jest ona umieszczona w osobnym pliku i nie ma siły, żeby nie była ona załadowana. Jest to pewna niekonsekwencja. Skoro autorzy przyjęli zasadę, że plik może zawierać więcej niż jedną klasę, przecież można było wszystko podzielić tak, by rzeczywiście system mógł uruchomić całą podstawową funkcjonalność z jednego pliku. Ostatecznie operacje dyskowe trochę kosztują.

Usprawnienia API oceniam ogólnie mimo wielu niekonsekwencji na plus, lecz zastanawia mnie usilne pragnienie trzymania się wstecznej kompatybilności. Ostatecznie jest to wersja "3", bez żadnego jeszcze ważniejszego numerka. Co innego język programowania, a co innego biblioteka. Ktoś, kto napisał aplikację na Smarty 2 przecież i tak nie będzie mieć zbytniej korzyści z przesiadki, jeśli nie będzie wykorzystywać nowej funkcjonalności, dlaczego więc męczyć się z anachronizmami, kiedy taka zmiana to znakomita okazja do oczyszczenia kodu?

Rodzaje szablonów

Począwszy od wersji 3.0 Smarty dopuszcza tworzenie szablonów w czystym PHP (po uprzednim aktywowaniu tej opcji). Takie szablony nie podlegają kompilacji, lecz są z miejsca dołączane do wykonywanego skryptu. Rodzaj szablonów wybiera się dość prosto:

$smarty->display('php:szablon.php');

O zaletach czy wadach takiego podejścia nie będę się rozwodzić, zapamiętując jedynie, że taka opcja jest i jeśli ktoś chce, może z niej zawsze skorzystać. Możliwe jest także wczytanie szablonu ze zmiennej:

$smarty->display('string:Hi universe: {$hiUniverse}');

Prawdę mówiąc na razie nie potrafię sobie wyobrazić praktycznego zastosowania, ale zwiększoną elastyczność doceniam.

Składnia szablonów

Cóż, rewelacji nie ma. Smarty 3 jest wstecznie zgodny składniowo ze Smartym 2, a składnia została jedynie rozszerzona o nowe możliwości. Dalej bawimy się klamerkami, kompilator dalej nie rozumie tego, co jest w statycznym tekście, dalej mamy mnóstwo średnio użytecznych funkcji, które przede wszystkim doskonale replikują funkcjonalność czystego PHP. Z nowości, autorzy chwalą się zabudowaniem w kompilatorze prawdziwego leksera i parsera wyrażeń, dzięki czemu wreszcie możliwe jest pisanie rzeczy w stylu $foo = strlen($text) * 17 - bar($zmienna). Oczywiście nie wspomniano o tym, że parę systemów szablonów, wliczając w to OPT 1.x oraz 2.x, ma takie coś już od lat...

Szkoda, że autorzy w dalszym ciągu pozostają odporni na jakiekolwiek głosy rozsądku ze strony programistów, którzy powtarzają w kółko: po co nam język szablonów, który przede wszystkim naśladuje PHP, i to nieudolnie? Ludzie, którzy fascynują się składnią Smarty'ego i im podobnych systemów po pewnym czasie zrażają się do niej, gdy widzą, że prawie dokładnie tak samo pisze się w czystym PHP, a na dodatek później zamiast wieszać psy na Smarty'm, wieszają je na systemach szablonów jako takich. A za bezmyślność twórców płacą dodatkowo Bogu ducha winne porządne systemy szablonów mające nieco wyższe ambicje...

Nowości w funkcjach

Niestety tutaj, podobnie jak w wielu innych miejscach muszę opierać się na szczątkowych informacjach. W paczce z biblioteką jest jedno prymitywne demo, niedokończony README i tyle. Żadnych testów jednostkowych, żadnej namiastki dokumentacji. Dlatego mogę mieć tylko nadzieję, że nie walnąłem gdzieś poważnej gafy.

Najważniejszy dodatek to pojawienie się dziedziczenia szablonów. Formuła jest nawet zbliżona do tego, co mamy np. w Open Power Template 2, czyli dziedziczenie statyczne:

{extends file='base.tpl'}
{block name='list'}
<li>{$list[i].var1}, {$list[i].var2}</li>
{/block}

plik bazowy:

<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
 <head>
  <title>Strona WWW</title>
 </head>
 <body>
  <h1>Strona WWW</h1>
  <ol>
  {section name=i loop=$list}
    {block name='list'}{/block}
  {/section}
  </ol>
 </body>
</html>

Bloki, czyli odpowiedniki snippetów z OPT, działają na zasadzie przeklejenia kodu źródłowego w wybraną lokalizację podczas kompilacji, dzięki czemu taki blok od razu integruje się np. z sekcją. Bloki nie muszą koniecznie nadpisywać wcześniej zdefiniowanych bloków o identycznej nazwie, lecz np. doklejać się na koniec już zdefiniowanych, jeśli dodamy do nich atrybut append. Możliwe jest także składanie dynamiczne po stronie skryptu:

$smarty->display('extends:grandchild.tpl|child.tpl|parent.tpl');

Interesująco rysuje się także możliwość definiowania funkcji bezpośrednio w szablonie, które mogą mieć argumenty i które możemy później osadzać w różnych miejscach:

{function name=item element}
  <li>{$element.var1}, {$element.var2}</li>
{/function}
<ol>
  {section name=i loop=$list}
    {item element=$list[i]}
  {/section}
</ol>

W miejsce sekcji pozostawionych jedynie dla kompatybilności, Smarty 3 wprowadza nowe oraz ulepsza stare pętle: for, foreach oraz while, które teraz już wyjątkowo mocno przypominają swoje odpowiedniki w PHP i rodzą pytanie, jaki jest sens stosowania takiego języka szablonów jako nakładki i alternatywy dla PHP...

Wydajność

Arghhh! To, co zrobił zespół Smarty z wydajnością swej biblioteki, woła o pomstę do nieba. Już Smarty 2 nie grzeszył szybkością, natomiast tutaj mamy istną optymalizacyjną tragedię. Ponieważ przygotowuję aktualizację mojego benchmarku systemów szablonów, postanowiłem włączyć do niego także trzecią odsłonę, aby porównać sobie, jak wypada ona wydajnościowo i powiem krótko: jest gorzej, niż źle. Optymalizacja sekcji leży całkowicie. Uzyskiwane czasy są o 50% gorsze, niż w dwójce. Użycie rekomendowanego foreach jedynie zbliża się do czasów sekcji z "dwójki". W ogóle użycie w szablonie jakiejkolwiek zmiennej działa wolniej, bo postanowiono, że w dostępie pośredniczyć będzie dodatkowa metoda. Praktycznie jedynie w ładowaniu biblioteki oraz w teście na treść pętli zdefiniowaną oddzielnie "trójka" wypadła lepiej, przy czym w tym ostatnim jedynie dzięki pojawieniu się funkcji. W życiu nie podejrzewałem także, że mimo zastosowania takiego samego mechanizmu obsługi dziedziczenia szablonów, Smarty 3 może być tutaj pięciokrotnie wolniejszy niż Open Power Template.

Podsumowanie

Niestety, potwierdziły się moje obawy. Mimo poczynienia wielu pozytywnych kroków, Smarty 3 rewolucją nie jest i najprawdopodobniej nie będzie, co naturalnie najprawdopodobniej nie przełoży się na popularność. Jeśli ktoś nie lubił Smarty'ego, wersja 3.0 wcale nie sprawi, że zmieni swoje nastawienie. Jeśli ktoś nie lubił języków szablonów a'la Smarty, także nagle ich lubić nie zacznie. Wszystko przez to, że ogrom nowości w trójce to rzeczy, które już od dawna można spotkać w wielu innych systemach szablonów, a sam język szablonów nie oferuje wiele ponad to, co można znaleźć w czystym PHP. Do tego dochodzi usilne pragnienie trzymania się wstecznej kompatybilności nawet za cenę przeniesienia złych i kiepskich praktyk programistycznych.

Gwoździem do trumny jest tragiczna wydajność wykonywania szablonów. Oczywiście zawsze można wykręcić się sianem, że to tylko wersja beta i wszystko się może zmienić do czasu finalnego wydania, ale bez przesady. Jeśli problemy z wydajnością zaszyte są w architekturze biblioteki i fundamentalnych założeniach projektowych, to nie da się ich tak od ręki usunąć. Tymczasem patrząc na kody skompilowanych szablonów, mam wrażenie, że mają one właśnie taki charakter... cache może dużo pomóc, ale nie jest to remedium na wszystkie bolączki. A przecież wystarczyło trochę pomyśleć - przykład Open Power Template'a pokazuje, że wydajność wcale nie musi kłócić się z możliwościami.

Powrót

Komentarze

Napisał matipl w piątek, 4 grudnia 2009 o 21:28

Świetnie, tyle lat mieli i nawet o krok się zespół nie posunął. Ale co się dziwić, jeśli na co dzień możliwe, że pracują z Smarty nie widząc konkurencji...

Napisał Michał w poniedziałek, 7 grudnia 2009 o 08:58

Masz dużą wiedzę na temat systemów szablonów - chętnie bym przeczytał Twoją opinię na temat Twiga (http://www.twig-project.org/). Może jakaś recenzja? ;)

Napisał Zyx w poniedziałek, 7 grudnia 2009 o 10:15

OK, o Twigu też coś się pojawi w takim razie.

Napisał skynetroot w poniedziałek, 25 stycznia 2010 o 02:44

Może odgrzebuję stary wpis, ale ciekawi mnie dlaczego system szablonów wg. Ciebie musi rozumieć dokument? Moim zdaniem nawet nie powinien. Czym różni się przetwarzanie html/xhtml od przetwarzania zwykłego tekstu(np. treści emaili)? Wystarczy, że wartości będą odpowiednio escapowane.

Popraw mnie jeśli się mylę.

Napisał Zyx w poniedziałek, 25 stycznia 2010 o 09:00

1. Masz automatyczne sprawdzanie składni. System szablonów odmówi łyknięcia szablonu z niedokmniętym znacznikiem, który inaczej mógłby wyjść na jaw wiele miesięcy później, nawet już po uruchomieniu strony. Powiedz sobie szczerze: kto normalny siedzi i przepuszcza każdą możliwą podstronę końcowej aplikacji przez W3C Validator, by upewnić się, że wszędzie są podomykane znaczniki? Mnie już to wielokrotnie ratowało z opresji.

2. System szablonów może taki kod od razu nieco posprzątać i np. dorzucić brakujące elementy.

3. Dzięki temu, że system szablonów wie, że <div id="cośtam"> to otwarcie znacznika, a nie przypadkowy ciąg znaków, może dużo lepiej i precyzyjniej zarządzać jego atrybutami, nazwą znacznika itd. W OPT jest cała rodzina czytelnych i eleganckich instrukcji odpowiadających za dynamiczne zarządzanie atrybutami, które nie mają szansy działać, jeśli szablon jest traktowany jako statyczny tekst. Spróbuj sobie napisać w Smartym kod generujący dynamicznie atrybuty, osadź go we wnętrzu znacznika, a później oceń czytelność tego kodu, gdzie > może być np. 10 linijek niżej.

4. W OPT komponenty mogą modyfikować istniejące atrybuty znaczników HTML, jeśli sobie tego zażyczymy, by np. podmienić klasę CSS, gdy formularz jest źle wypełniony. To też działa głównie dzięki temu, że OPT wie, co to są atrybuty.

Napisał skynetroot w poniedziałek, 25 stycznia 2010 o 12:46

Dzięki za szybką odpowiedź.

W takim razie mam inne podejście do systemu szablonów. Wg mnie to koder html powinien dbać o to, czy statyczna część szablonu jest poprawna czy nie.

Pytam nie bez powodu bo sam zamierzam napisać własny system, ale żeby zrobić to dobrze najpierw przeglądam istniejące projekty.

Mi przykładowo nie odpowiadają języki szablonów oparte o XML, bo są nieczytelne(tagi xml mieszają się z html). Z tego co znalazłem w internecie podoba mi się mako(http://www.makotemplates.org/). Podobno najbardziej zaawansowany projekt dla pythona. Jestem ciekaw co o nim sądzisz. Miałeś styczność?

Napisał Zyx w środę, 27 stycznia 2010 o 15:40

A w nie-XML-owych to się może nie mieszają? Mieszają się, i to dużo bardziej, bo nie ma nad tym żadnej kontroli, gdzie można je osadzać. OPT i PHPTAL są wybitnie nieinwazyjne dzięki XML-owi, a szablon naprawdę wygląda dużo czytelniej i to jest podstawa, by się nic nie mieszało. Atrybuty i znaczniki mają inną przestrzeń nazw, więc nie problem je rozróżnić.

Ad. kodera -> dobra, a jak on niby ma o to dbać? Ręcznie ślęczeć nad kodem, sprawdzając linijka po linijce, czy ten mega-wypasiony algorytm, który napisał, bo nie miał OPT, który to robi w jednej linijce, nie generuje przypadkiem nadmiarowych klamerek? Czy przypadkiem gdzieś nie zgubił zamknięcia znacznika?

Ogólnie poszukaj sobie w archiwum wpisu "Użyteczne systemy szablonów", tam jest dużo więcej o całej problematyce. Systemy szablonów to trudna tematyka. Aby zrobić to dobrze, zarezerwuj sobie najbliższe 2-3 lata na myślenie i pisanie, bo jeśli to ma się skończyć "jeszcze jedną nakładką opakowującą zwykłe PHP w klamerki", to lepiej zająć się czymś pożyteczniejszym. A Mako działa mniej więcej na takiej zasadzie. To jest zwykły Python opakowany w znaczniki do osadzania go w HTML-u, parę dodatkowych interfejsów i nic więcej. Jak programiści chcą używać takiego prymitywizmu, to dobra - ich wybór, ale dla mnie wykorzystanie języka algorytmicznego do pisania szablonów to masochizm marnujący cały potencjał idei.

Napisał skynetroot w czwartek, 28 stycznia 2010 o 18:23

Ok, poznałem Twoje zdanie, chociaż niezupełnie je podzielam.

Mówiąc o mieszaniu miałem na myśli, że łatwiej wizualnie odróżnić np. smartowe klamerki {} albo tbsowe [] niż <opt:cos_tam> w pliku html.

Szczerze mówiąc nie wiem dlaczego xmlowe podejście ma być mniej inwazyjne.

Do kodowania html korzysta się z edytora, który wspomaga kodowanie html. Tak, jak do programowania używa się porządnego IDE. Przecież nikt nie pisze html w notatniku windowsowym.

Ten wpis czytałem, zajrzałem sobie jeszcze przed chwilą i jest w nim sporo racji. Ale system szablonów nie musi mięc języka szablonów. np symfony ma system(moim zdaniem słaby), a nie ma języka.

Swoją drogą - dla mnie to co nazywasz prymitiwizmem, dla mnie jest prostotą.

Napisał pmadry w piątek, 19 marca 2010 o 21:06

"Smarty 2 to jeden z gorszych istniejących systemów szablonów, który żyje jedynie dzięki swej nieuzasadnionej popularności."
OK.
Skoro już popełniłem to zło czy mam jakieś wyjście z sytuacji?
Mam (prawie) gotowy serwis usługowy zrobiony w tandemie PHP-Smarty. Nawet gładko chodzi.
Dodam, że będę musiał jeszcze zaimplementować mechanizmy asynchroniczne dla uzywających JS.
Czy w tej konfiguracji będzie to proste jak z HTML?

I tu też jeszcze nie wiem co najlepiej zastosować?
JQuery, XAJAX (te dwie technologie zgrubsza poznałem). Ale czy któryś z nich "sięgnie" do węzłów w Smarty (lub/i do PHP)?
Jeśli pytania wygladają głupio to dlatego, że jeszcze nie próbowałem a po lekturze Twoich wpisów nie wiem, czy tracić na to czas czy od razu pożegnać się ze Smarty?
A jeśli tak to jak z tego wybrnąć?
Czy Twoje OPT to jakaś alternatywa w tym przypadku?

Napisał Zyx w sobotę, 20 marca 2010 o 08:47

Zmiana technologii to poważna sprawa i niesie za sobą pewien koszt. Musisz sobie sam odpowiedzieć, czy opłaca się go ponosić, bo to zależy od planów na przyszłość - jeśli serwis jest stale rozbudowywany, przejście na technologię, która w dłuższej perspektywie ułatwi życie jest jak najbardziej opłacalne. Spójrz na mój blog. Cały czas śmiga on na OPT 1.0, ponieważ migracja oznacza de facto przepisanie całego kodu od nowa, a to się nie udaje od ponad pięciu lat. Musisz wziąć też pod uwagę znajomość nowej technologii (nawet najlepsze rzeczy nieumiejętnie stosowane bardziej zaszkodzą niż pomogą) i tego typu czynniki.

Natomiast w przypadku nowych projektów jak najbardziej możesz zacząć eksperymentowanie z nowymi technologiami, jak OPT.

Odpowiadając na drugie pytanie -> OPT nie ma nic wspólnego z JS/AJAX. Tę bibliotekę średnio obchodzi, co robisz z tym kodem HTML po odebraniu go w przeglądarce, ponieważ ona pracuje po stronie serwera. Co najwyżej może pomóc generować odpowiedzi AJAX na serwerze, ale nic poza tym. OPT koncentruje się na generowaniu treści po stronie serwera i do przeglądarki wysyła gotowe wyjście, na którym pracuje JS - jak każdy system szablonów. Różnica między OPT a np. Smarty polega na inteligentniejszym i bardziej przejrzystym sposobie generowania tego wyjścia.

Pamiętaj, dbaj o kulturę wypowiedzi oraz dyskusji w sieci.

Skomentuj

NickInformacja
E-mailNa wypadek potrzeby kontaktu z autorem (niepublikowany)
BlogNie zapomnij o http://
LayoutNapisz tu, czy widzisz dzienny czy nocny layout.
WpisFormatowanie wikiKomentarze są moderowane - przeczytaj zasady!

Na Zyxist.com panuje swoboda wyrażania opinii oraz krytyki pod dowolnym adresem. Jedyny warunek: musi być ona kulturalna i rzeczowa. Na chamstwo, prostactwo lub jawne obrażanie kogokolwiek nie ma tu miejsca i takie komentarze są bardzo szybko usuwane. Jeśli zamierzasz polemizować z treścią wpisu, wpierw uważnie ją przeczytaj.

© Tomasz "Zyx" Jędrzejewski 2005 - 2010 | Wykonanych zapytań: 2 | Serwer wirtualny zapewnia