PHP-s sablonrendszerekkel nemhogy Dunát, de Amazonast lehet rekeszteni. Van egy nagy halom megoldás, az egyszerűtől, a komplex MVC rendszerekig. Sok helyen olvasni, hogy ha csak sablonkezelésről van szó, és nincs szükség az üzleti logika és az adatbázist kezelő réteg szétválasztására, akkor a PHP, mint sablonnyelv is tökéletesen megfelel a maga HTML-be ágyazhatóságával. Ezzel a megközelítéssel tökéletesen egyetértek, és a legtöbb projektnél bőven elég is. Gondoljuk csak bele, a legtöbb MVC rendszer view-ja is ezen az elven alapul: Készítünk egy, vagy több sima HTML kódot tartalmazó sablonfájlt, aztán a sablonmotor által rendelkezésünkre bocsájtott változókkal és/vagy függvényekkel a megfelelő helyre illesztjük a controller által generált tartalmat. Személy szerint ahelyett, hogy meglévő komponenseket bogarásztam volna, egyszerűbbnek találtam egy saját megoldás elkészítését.
A dolog lelke nem más, mint a kimeneti puffer, amit minden oldal generálásakor "elkapunk". Úgy kell elképzelni a folyamatot, hogy a kliens meghívja a valami.php-t, ami erre elkezdi futtatni a saját kódját, beinclude-olja, amit be kell include-olnia (adatbázis burkoló osztály, hibakezelő kódok, naplózás, stb, stb, illetve a saját sablonosztályunkat is, aminek törzse lényegében így néz ki:
class Sablon {
/**
A végső kimenet HTML kódját tartalmazó változó
@access private
@var string
/
private $HTML_out;
/**
A laphoz tartozó sablon HTML kódját tartalmazó változó
@access private
@var string
/
private $HTML_tpl;
/**
Sablonkezelő konstruktora
Bemenő paramétere a sablonfájl
@param string $HTML_tpl
/
public function __construct($HTML_tpl)
{
if(file_exists($HTML_tpl)) {
$this->HTML_tpl = file_get_contents($HTML_tpl);
} else {
throw new Exception("A '".$HTML_tpl."' sablon nem telálható!");
}
}
/**
Sablon értelmezését végző függvény
@access private
/
private function parser()
{
//itt elvégzünk pár lényegi műveletet - lásd lejjebb a magyarázatot
$this->HTML_out = str_replace("<CONTENT>", ob_get_contents(), $this->HTML_out);
}
/**
Kimenet küldése
@access public
/
public function out()
{
$this->parser(); //lefuttatjuk az értelmezőt
ob_clean(); //kiürítjük a szerveroldal pufferét
echo $this->HTML_out; //az értelmező által generált tartalom kerül a pufferbe
ob_end_flush(); //elküldjük a puffer tartalmát a kliensnek
}
}
A fenti osztály működését tekintve nagyon egyszerű: Amikor a lekért PHP oldal generálása megkezdődik (miután példányosítottuk a Sablon osztályt), a $HTML_tpl adattagba kerül a legenerálni kívánt sablon – benne a szokásos kiegészítő változókkal. A példában az egyszerűség kedvéért csak egy ilyen van, a <CONTENT>. Egy életszerű esetben nyilván több ilyen sablonváltozóra lenne szükség, sőt bonyolultabb illesztésekkel más műveletek is megvalósíthatók (például sablonok rekurzív egymásba ágyazása).
Az script eztán szépen rendben fut tovább, és generálja az oldal kimenetét, elvégzi azokat a feladatokat, amiket összefoglaló néven üzleti logikának nevezünk (most ide értem az adatbázis-műveleteket is). Amikor az oldal kimenete teljesen elkészült, nincs is más hátra, mint meghívni a Sablon objektum out() metódusát, ami elindítja a munka oroszlánrészét végző parser()-t, majd a végső kimenetet elküldi a böngészőnek. A parser() végzi el a sablon, és a PHP script által generált kimenet "összegyúrását" azáltal, hogy a törzsében definiált műveleteket elvégzi. Ez lényegében azt jelenti, hogy a sablonban definiált kifejezéseket valamilyen mintaillesztéssel felismeri, és lecseréli a pufferben tárolt kimenet megfelelő részével.
Egy példakód, az egyszerűség kedvéért:
pelda_sablon.tpl:
<html>
<head>
<title>Tesztoldal</title>
</head>
<body>
<p>Ez itt a script kimenete: <b><CONTENT></b></p>
</body>
</html>
valami.php:
<?php
require 'class.Sablon.php'; //a fenti osztályt tartalmazó állomány
$tpl = new Sablon('pelda_sablon.tpl');
//akármilyen művelet
echo "Hello World!";
$tpl->out();
?>
E
ztán a kimenetben a Hello World szöveg beíródik a sablon HTML kódjában a <CONTENT> helyére.
A példában használt <CONTENT> természetesen tetszés szerint helyettesíthető akármilyen, akárhány illesztéssel (pl. Smarty-ban a {$valtozo} cseréje történik meg, a Zend Viewban a $this->valtozo értéke kerül beillesztésre). Mindkét rendszerben lehetőség van a sablonon belül függvények hívására (pl.: {$valtozo|nl2br}). Én ezt nem tartom túl jó ötletnek, mivel ezzel megszegjük azt a szigorú feltételt, amit szándékosan szabtunk magunknak a kód, és a megjelenítés szétválasztására.
A fenti példa borzasztóan leegyszerűsítve bemutat egy lehetséges módszert a PHP-vel történő sablonkezelésre a kimeneti puffer használatával. Az itt bemutatott Sablon osztály parser() metódusának kibővítésével tetszőlegesen komplex sablonkezelés valósítható meg. Ez főleg azoknak nyújthat segítséget, akik még csak most kísérleteznek a kód és a megjelenítési réteg szétválasztásával, és még nem szoktak hozzá semmilyen meglévő sablonmotor használatához.