e-mail:

Szablony

Autor: Adam Major
Artykuł został pierwotnie opublikowany w magazynie Software 2.0 Extra! nr 1 - "PHP Starter Kit" (10/2002) Software 2.0 Extra
www.software.com.pl
 

Uwaga: Druga część artykułu, pt. "Zaawansowane możliwości Smarty"

Jedna z głównych cech języka PHP - umieszczanie kodu wraz z HTMLem - choć na początku może się wydawać wielką zaletą, nie w każdej sytuacji nią jest. W przypadku dużych aplikacji, tworzonych przez kilku ludzi, ten sposób programowania może się bardzo niekorzystnie odbić na wydajności zespołu oraz czasie potrzebnym na modyfikację i aktualizację aplikacji. Każda zmiana szaty graficznej będzie wymuszała zaangażowanie programisty, który wprowadzi lub zmodyfikuje (w wielu plikach) odpowiednio kod HTML. Ingerencja w kod skryptu może spowodować powstanie błędów (choćby popularne błędy ze znakami " i '), które będzie trzeba wyłapać podczas żmudnych testów.

Wykorzystanie szablonów umożliwia pełne odseparowanie warstwy prezentacyjnej od warstwy biznesowej aplikacji. Grafik może dowolnie zmieniać szatę graficzną bez obawy, że cokolwiek popsuje w skrypcie. Natomiast programista nie musi integrować HTML'a z kodem PHP co znacznie zwiększa przejrzystość programu i ułatwia jego późniejszą pielęgnację.

Technika szablonów polega na stworzeniu zwykłych plików HTML (zwanych dalej szablonami) zawierających specjalne znaczniki (w większości systemów można użyć znacznika o postaci {zmienna} lub {$zmienna}) następnie programista w aplikacji definiuje znaczniki i przypisuje im wartości ze zmiennych PHP lub bezpośrednio z łańcucha znaków. Każdorazowo przy przetwarzaniu skryptu system szablonów wyszukuje wszystkie znaczniki użyte w szablonie i podstawia pod nie odpowiednie wartości.

Programista definiuje tylko znacznik szablonu oraz przypisuje do niego wartość, nie interesuje jego jak i gdzie będzie wyświetlana zawartość zmiennej. Natomiast grafik podczas modyfikacji szaty graficznej może dowolnie zmieniać położenie znaczników oraz ich formatowanie bez obawy, że jego zmiany będą miały wpływ na nieprawidłowe działanie aplikacji.

Zalety i wady

Niestety żadne rozwiązanie, czy też technologia nie jest pozbawiona wad z którymi musimy się pogodzić, jeśli zamierzamy ją stosować. Tak także jest z systemami szablonów jednak ich zalety przeważają wady oraz kompensują zainwestowany czas potrzebny na opanowanie tej techniki.

Do zalet szablonów należy zaliczyć:
- odseparowanie kodu aplikacji od jej warstwy prezentacyjnej
- tworzenie kodu bardziej przejrzystego i łatwiejszego w pielęgnacji
- zwiększenie wydajności zespołu, który teraz nie musi dublować się przy wprowadzaniu modyfikacji
- znaczne zmniejszenie ilości kodu, a tym samym potencjalnych miejsc w których mogą pojawić się błędy
- ułatwienie tworzenia wielu wersji szat graficznych w serwisach, które umożliwiają użytkownikowi
  dokonanie wyboru szaty graficznej lub warunkują jej wybór np. na podstawie pory dnia czy też roku.

Wada szablonów jest tylko jedna:
- nieznaczne spowolnienie działania serwisu spowodowane przetwarzaniem szablonów.

W sieci można znaleźć kilkanaście systemów szablonów o różnej funkcjonalności, sposobie obsługi oraz szybkości działania. Wybranie więc odpowiadającego nam systemu nie jest zbyt proste. Przy jego wyborze powinniśmy się kierować takimi czynnikami jak rodzaj funkcji jakie udostępnia system. Oprócz prostego podstawiania znaczników, niezbędne są również operacje na blokach (sekcjach) - pozwalające grupować wybrany fragment szablonu oraz wielokrotnie go przetwarzać (w pętli) - funkcja ta jest przydatna np. przy generowaniu zmiennej liczby rzędów tabeli na podstawie rekordów pobranych z bazy danych.

Drugim ważnym czynnikiem wyboru jest sposób obsługi. Niestety jest on bardzo subiektywny, więc jedyną możliwością doboru właściwego systemu jest zapoznanie się z kilkoma najbardziej popularnymi rozwiązaniami.

Test wydajnościowy

Przeglądając zasoby sieci można znaleźć zaledwie kilka testów porównujących wydajność systemów szablonów. W większości są one tworzone przez autorów klas, więc badają oni zwykle takie przypadki zastosowania szablonów w których ich system wypada najlepiej na tle konkurencji. Przez to wyniki testów są mało wiarygodne, a badane zastosowania niezbyt interesujące np. 100 krotne przetwarzanie 10 kB szablonu zawierającego 15 znaczników.

Postanowiłem więc stworzyć test, który opierałby się o praktyczne zastosowanie szablonów w prawdziwych aplikacjach. Test podzieliłem na dwie części, przedstawiające strony WWW prezentujące dane na dwa sposoby:
1. Strona wyświetlająca dane na temat jednego klienta.
Test polegał na prostym podstawieniu wartości pod 15 znaczników znajdujących się w pliku HTML o rozmiarze 1889 bajtów.

2. Tabela z 20 wierszami zawierającymi szereg informacji o klientach.
Do wyświetlenia danych w tabeli wykorzystano operacje na bloku powielanym 20 razy. Każdy wiersz zawierał po 6 znaczników. Dodatkowo zastosowano proste podstawienie 6 znaczników, bardzo typowe przy tego rodzaju stronie np. wyświetlenie ilości zwracanych rekordów, tekstu informacyjnego, nawigacji po stronach z wynikami itp.

Do testu zakwalifikowałem 8 najbardziej popularnych systemów szablonów, które posiadały możliwość obsługi bloków. Testy zostały wykonane na komputerze: Duron 800, 128 MB RAM, dysk Seagate Barracuda III; pracującym pod kontrolą systemu Linux Mandrake 8.1, Apache 1.3.20 oraz PHP 4.2.1. Podczas trwania testów komputer nie był obciążony innymi zadaniami.

Na test składały się dwa rodzaje pomiarów: czas wykonania skryptu uruchomionego za pomocą przeglądarki WWW oraz ilość stron wywołanych w ciągu sekundy, mierzonych za pomocą programu ApacheBench 1.3 c (polecenie ab -n300 http://localhost/artykul/nazwa_systemu/nazwa_testu). Test ten był także dobrą okazją do sprawdzenia jaki wpływ na wydajność ma zastosowanie programów typu PHP accelerator, które rozszerzają język PHP o funkcje automatycznie buforujące wyniki działania skryptów na dysku.

Pomiar czasu dla każdego systemu był wykonywany 4 razy (zachowując ok. 5 sekundową przerwę pomiędzy odświeżeniami strony), następnie po odrzuceniu pierwszej (największej) wartości obliczana była średnia arytmetyczna. Tak samo było w przypadku stosowania programu ab z tym, że wykonywano tylko 3 pomiary.

O kolejności w tabelach wyników decydowała średnia liczba wywołań na sekundę obliczona z wyniku systemu przy PHP accelerator'ze włączonym i wyłączonym.

Wyniki testów wydajnościowych
Rysunek 1. Wyniki testów wydajnościowych

Wyniki testów mogą być dużym zaskoczeniem (a nawet szokiem) dla zwolenników Smarty. Mimo całej zaawansowanej techniki kompilacji system ten jest bardzo wolny w przypadku stosowania czystego PHP, zwycięża jednak w obu testach gdy włączymy obsługę PHP acceleratora.

Osoby, które potrzebują największej wydajności i nie mogą zainstalować PHP acceleratora lub programu o podobnych możliwościach będą musiały wybrać inny system np. Bugi, Phemplate.

Wprowadzenie do Smarty

Smarty jest jednym z najbardziej rozbudowanym systemów szablonów, oferuje unikalne opcje mające na celu zwiększenie szybkości działania systemu oraz ułatwienie pracy osobom przygotowującym szablony stron. Autorami projektu Smarty są takie znakomitości świata PHP jak Monte Ohrt i Andrei Zmievski (jeden z głównych programistów rozwijających język PHP).

W celu przyspieszenia pracy systemu zastosowano technikę kompilacji, polegającą na jednokrotnym przetwarzaniu szablonu do postaci zwykłego skryptu PHP, przy następnych wywołaniach Smarty korzysta ze skompilowanego szablonu. Jeśli dokonamy modyfikacji w szablonie, system wykryje to (gdy jest włączona opcja compile_check) i dokona ponownej kompilacji. Z założenia mechanizm ten miał drastycznie przyspieszyć wykonywanie skryptu, działa to tak jak planowano tylko w przypadku stosowania akceleratora języka PHP np. PHP accelerator.

Wśród innych zaawansowanych cech Smarty należy wymienić: system buforujący (cache) wygenerowanych stron, modyfikatory zmiennych, funkcje szablonów, wtyczki (plug-ins), filtry i pliki konfiguracyjne.

Instalacja Smarty

Czynność ta jest bardzo prosta, polega na utworzeniu w katalogu naszego projektu, dwóch podkatalogów templates, templates_c oraz cache i configs (oba opcjonalnie). Do tego katalogu także należy skopiować z archiwum systemu Smarty: katalog plugins oraz pliki Smarty.class, Smarty_Compiler.class oraz Config_File.class (opcjonalnie). Podstawowa struktura projektu została pokazana na rys2.

Katalogi templates_c oraz cache (oznaczone na rysunku kolorem czerwonym) musza mieć ustawione prawa do zapisu dla użytkownika na którego prawach działa serwer WWW. W przypadku użytkownika apache starczą prawa 700 oraz ustawiony właściciel jako apache:apache. Oczywiście w warunkach testowych możemy zaryzykować nadanie praw 777.
  Podstawowa struktura projektu używającego Smarty
Rysunek 2. Podstawowa struktura projektu używającego Smarty

W dalszej części artykułu przedstawiłem podstawowe informacje umożliwiające rozpoczęcie korzystania ze Smarty. Więcej wiadomości czytelnik znajdzie w bardzo dobrej i przystępnie napisanej dokumentacji tego projektu.

Pierwszy szablon

Poznawanie systemu zaczniemy od bardzo prostego przykładu, który realizuje podstawienie dwóch znaczników w naszym szablonie.

Tworzymy plik szablonu o nazwie p1.tpl (oczywiście nazwa i rozszerzenie może być dowolne) i umieszczamy w katalogu templates. Zawartość tego pliku została pokazana na listingu 1.

W podanym przykładzie mamy dwa znaczniki {$tytul} oraz {$test_znacznika}, teraz napiszemy skrypt zamieniający znaczniki na wybrane przez nas wartości.
Skrypt należy zapisać w głównym katalogu projektu.

Jak widać obsługa Smarty nie wymaga stosowania żadnych zawiłych konstrukcji. Po zaimportowaniu biblioteki, tworzymy obiekt $smarty (linia 5) następnie przypisujemy wartości do znaczników za pomocą konstrukcji:
$smarty->assign('nazwa_znacznika', 'Wartość lub nazwa $zmiennej PHP lub wyrażenie matematyczne');
Rozpoczęcie przetwarzania szablonu zaczyna się po wywołaniu metody display, której argumentem jest nazwa szablonu.

 
<html>
<head>
<meta http-equiv="Content-type"
content="text/html;charset=ISO-8859-2">
<title>{$tytul}</title>
</head>
<body bgcolor="#FFFFFF">
{$test_znacznika}
</body>
</html>
Listing 1 Pierwszy szablon - p1.tpl

<?php
$tytul = 'Szablony - przykład 1';

include('Smarty.class.php');
$smarty = new Smarty;
$smarty->assign('tytul', $tytul);
$smarty->assign('test_znacznika',
 'To naprawdę działa!');
$smarty->display('p1.tpl');
?>
Listing 2 Podstawianie wartości pod znaczniki

Przejdźmy teraz do bardziej zaawansowanych funkcji a mianowicie:

Operacje na blokach

Jak wcześniej wspomniałem blok to wydzielony fragment szablonu, który będzie powielany n razy, co przydaje się do generowania różnych tabel, list itp. Aby za bardzo nie zaciemniać przykładu do wcześniej użytego szablonu dodamy blok który będzie wstawiał 10 liczb: 0, 5, 10 ...45.

Zapiszmy powyższy przykład do pliku p2.tpl. Pojawiły się nowe elementy, które wymagają wytłumaczenia. Cały blok zawarty jest w znacznikach {section ....} oraz {/section}. Będzie on powielany loop razy. W tym przypadku 10, ale może to być oczywiście określone za pomocą zewnętrznej zmiennej, która będzie zależna np. od ilości rekordów zwróconych z zapytania SQL. Znacznik {$liczby[blok]} oznacza, że znacznik {$liczby} jest tablicą, która będzie indeksowa za pomocą nazwy tego bloku - blok - i będzie się zmieniać od 0 do loop, przy czym możliwe jest także określenie od jakiego indeksu ma się zaczynać odliczanie (np. start=5) oraz z jakim krokiem (np. step = 10).

Przypisywanie do znacznika zmiennych tablicowych wygląda dokładnie tak samo jak w przypadku zwykłych zmiennych. Jeśli chcielibyśmy wprowadzić zmienną określającą ilość powtórzeń sekcji to w pliku szablonu stosujemy konstrukcję loop=$ile, a skrypcie obsługujemy znacznik {$ile} tak samo jak każdy inny.

 
<html>
<head>
<meta http-equiv="Content-type"
 content="text/html;charset=ISO-8859-2">
<title>{$tytul}</title>
</head>
<body bgcolor="#FFFFFF">
{$test_znacznika}<br /><br />
Test bloku:
{section name=blok loop=10}
{$liczby[blok]}<br />
{/section}
<br />Koniec bloku
</body>
</html>
Listing 3 Szablon prezentujący operacje na blokach - p2.tpl

<?php
$tab = array (0,5,10,15,20,25,30,35,40,45);

include('Smarty.class.php');
$smarty = new Smarty;
$smarty->assign('tytul',
  'Szablony - przykład 2');
$smarty->assign('test_znacznika',
 'To naprawdę działa!');
$smarty->assign('liczby',  $tab);
$smarty->display('p2.tpl');
?>
Listing 4 Przypisanie zmiennej tablicowej do sekcji szablonu

Modyfikatory

Pozwalają grafikowi na manipulowanie (w dość małym, lecz istotnym zakresie) informacją jaka zostanie podstawiona pod znaczniki. Z najważniejszych modyfikatorów należy wymienić: formatujące datę, obcinające łańcuch do podanej długości, zmieniające wszystkie litery w łańcuchu na duże lub małe, podstawiające przygotowaną informację gdy zmienna określająca znacznik jest pusta lub jest on nie zdefiniowany.

W przykładzie nie definiujemy znacznika {$tytul} dlatego zostanie wstawiona wartość domyślna. Modyfikator default może posłużyć do wstawienia znaku spacji (&nbsp;) w te komórki tabeli gdzie spodziewamy się, że skojarzona ze znacznikiem zmienna może być pusta. Istotne to jest w przypadku Netscape Navigatora, który wymaga aby komórka miała jakąś zawartość.

Przykład ten nie wyczerpywał wszystkich możliwości modyfikatorów, które są kolejnym krokiem do odseparowania pracy programisty oraz grafika.

 
<html>
<head>
<meta http-equiv="Content-type"
 content="text/html;charset=ISO-8859-2">
<title>{$tytul|default:"nie podano"}</title>
</head>
<body bgcolor="#FFFFFF">
{$znacznik}<br />
{$znacznik|upper}<br />
{$znacznik|truncate:10:"":true}
</body>
</html>
Listing 5 Szablon prezentujący zastosowanie modyfikatorów znaczników - p3.tpl
<?php
include('Smarty.class.php');
$smarty = new Smarty;

$smarty->assign('znacznik',  'Jakiś dłuższy
 tekst, który będziemy modyfikować.');
$smarty->display('p3.tpl');
?>
Listing 6 Zastosowanie modyfikatorów

Instrukcje warunkowe

Pozwalają na określenie zachowania szablonu na podstawie stanu (zawartości) znacznika, za pomocą instrukcji warunkowej {if} {/if}. Oprócz dobrze znanych warunków np. < > !=, Smarty umożliwia stosowanie tak specyficznych jak np. is even (parzysty), is odd (nieparzysty).

Jednym z najczęstszych zastosowań instrukcji warunkowych jest naprzemienne kolorowanie tła wierszy tabeli.

Jeśli indeks sekcji b1 jest parzysty zostanie wstawiony tekst #E0F6FF w przeciwnym wypadku #ADD8E6.

W rzeczywistej aplikacji $row_cnt może być określany np. na podstawie ilości rekordów zwróconych za pomocą zapytania SQLowego. Dla MySQL'a można by więc napisać:
$row_cnt = mysql_num_rows($result);

 
<html>
<head>
<meta http-equiv="Content-type"
 content="text/html;charset=ISO-8859-2">
<title>Koloryzowanie naprzemiene tabeli</title>
</head>
<body bgcolor="#FFFFFF">
<table width="100" border="0">
{section name=b1 loop=$row_cnt}
<tr bgcolor="{if $smarty.section.b1.index
 is even}#E0F6FF{else}#ADD8E6{/if}">
<td>kolumna 1</td>
<td>kolumna 2</td>
{/section}
</table>
</body>
</html>
Listing 7 Szablon prezentujący instrukcje warunkowe - p4.tpl

<?php
$row_cnt = 10;
include('Smarty.class.php');
$smarty = new Smarty;
$smarty->assign('row_cnt',  $row_cnt);
$smarty->display('p4.tpl');
?>
Listing 8 Testowanie instrukcji warunkowej


Komentarze oraz bloki nie przetwarzane

W szablonie możemy umieścić komentarze, które będą całkowicie ignorowane przez system i nie znajdą się w kodzie strony wynikowej. Komentarze umieszczamy między znakami {* Komentarz *}. Jeśli chcemy oznaczyć jakiś fragment szablonu, aby nie był przetwarzany przez Smarty, należy otoczyć go znacznikami {literal} kod nie przetwarzany {/literal}. Czynność ta jest konieczna w przypadku stosowania w szablonie CSS lub JS, ze względu na występowanie w nich znaków { i } które byłyby błędnie interpretowane przez system szablonów.

Podsumowanie

Artykuł ten miał na celu nakłonienie czytelników do rozważenia zastosowania szablonów w swoich projektach. Mimo czasu jaki trzeba poświęcić na zapoznanie się zespołu z tą techniką, warto spróbować, ponieważ dobrze zastosowane szablony zmniejszają znacznie czas potrzebny na tworzenie kodu i jego modyfikacje. Ograniczają również konieczność częstych kontaktów pomiędzy członkami zespołu.

Mam nadzieje, że prezentowany test ułatwi czytelnikom wybór najwłaściwszego dla nich systemu szablonów. Dzięki zamieszczeniu na CD pełnego kodu testu będą mogli również zapoznać się z podstawami obsługi testowanych systemów oraz wykonać podobny test we własnym środowisku.

Mimo słabych wyników czasowych (bez zastosowania PHP acceleratora) polecam system Smarty, który udostępnia najwięcej możliwości jest prosty w użyciu oraz ma bardzo dobrą i obszerną dokumentację.

Linki


Bugi Template http://www.bugi.biz
Easy Template System http://ets.sourceforge.net
PEAR http://pear.php.net
Phemplate http://pukomuko.esu.lt/phemplate/
Smarty http://smarty.net/
TemplatePower http://templatepower.codocad.com
vLIB Template http://www.activefish.com/vlib
xTemplate http://sourceforge.net/projects/xtpl

PHP Accelerator http://www.php-accelerator.co.uk

szablony.zip (102 KB) - Listingi, test wydajnościowy wraz ze źródłami systemów szablonów