В первой части мы по всем правилам ООП создали шаблонизатор, теперь наростим его мощь, будем делать это двумя способами:
- Расширая класс Amdy_Templater
- С помощью классов-помощников.
Первый способ эллементарный:
class Amdy_Templater extends Amdy_Template_Abstract {
protected function escape($var, $mode = ENT_COMPAT) {
return htmlspecialchars($var, $mode);
}
}
а в шаблоне
1. teplater !<?=$this->escape($this->test, ENT_NOQUOTES)?>! teplater<br/>
можно и без второго параметра, но иногда очень важно чистить кавычки.
Второй способ позаковырестее.
Будем применять делегирование — когда свойства одного объекта передаются (делегируются) другому. Способ примерно таков:
class Foo {
public function functionFoo() {}
}
class Bar {
public function functionFoo() {
$foo = new Foo();
$foo->functionFoo();
}
}
Т.е. мы получаем нужный объект и вызываем его метод.
Интерфейс было решено не трогать, чтобы оставить возможность минимализма для извращенцев, менял абстрактный класс.
<?php
require_once('Amdy/Templater/Interface.php');
abstract class Amdy_Template_Abstract implements Amdy_Templater_Interface {
protected $_data = array();
protected $templateExt = '.tpl.php';
protected $_helper = array();
protected $_helperMethod = array();
public function __set($key, $value) {
$this->_data[$key] = $value;
}
public function __get($key) {
return isset($this->_data[$key]) ? $this->_data[$key] : null;
}
public function setTemplateExt($ext) {
$this->templateExt = $ext;
}
public function display($tpl) {
require($tpl . $this->templateExt);
}
public function fetch($tpl) {
ob_start();
$this->display($tpl);
$retVal = ob_get_contents();
ob_end_clean();
return $retVal;
}
public function addHelper($helper) {
$method = get_class_methods($helper);
foreach ($method AS $name)
if (in_array($name, $this->_helperMethod)) {
die("ERROR in " . __METHOD__ . " method `$name` exist in other helper");
}
$this->_helperMethod = array_merge($this->_helperMethod, $method);
$this->_helper[ get_class($helper) ] = $helper;
}
public function __call($method, $args = array()) {
if (in_array($method, $this->_helperMethod)) {
foreach ($this->_helper AS $helper) {
if (method_exists($helper, $method)) {
call_user_func_array(array($helper, $method), $args);
return true;
}
}
} else {
echo "ERROR in " . __CLASS__ . " method `$name` not exist in helper's";
}
}
}
?>
Добавились две переменные $_helper и $_helperMethod в первой будут храниться наши помощники, а во второй набор методов из помощников. Так же два метода — addHelper и магический __call. С помощью первого мы добавляем helper, при этом проверяя, чтобы не появилось одинаковых методов. во втором с помощью магии мы вызываем метод из helper-ов, обходя их с помощью foreach и проверяя с помощью method_exist существование и когда находим нужный helper вызываем его метод передавая параметры с помощью call_user_function_array. В php есть call_user_method_array, который, судя по названию кажется более пригодный, но он считается устаревшим и использовать его не рекомендуется, вместо этого мы передаём в качестве параметра массив с объектом и методом.
Теперь проверим навый функционал. Изменим шаблон
1. teplater !<?=$this->escape($this->test, ENT_NOQUOTES)?>! teplater<br/>
2. !<?$this->say('what', 'say')?>!<br/>
3. !<?$this->say2('what', 'say')?>!<br/>
И теперь делегируем новые методы say и say2
class test {
function say($say, $say2) {
echo "test say - $say, $say2";
}
}
class test2 {
function say2($say, $say2) {
echo "test2 say - $say, $say2";
}
}
require_once('Amdy/Templater.php');
$tpl = new Amdy_Templater();
$tpl->addHelper(new test());
$tpl->addHelper(new test2());
$tpl->test = '<u style="">test</u>';
$tpl->display('test');
Создали два класса test и test2, а у них методы say и say2. И с помощью addHelper перадаём их в шаблонизатор.
Ну и архивчег с кодом навсякий. скачать исходники
Поделиться в соц. сетях
Похожие посты:
почему end_clean, а не ob_end_clean, ведь буферизация продолжится?
зачем при вызове каждого метода пробегать по ним форичем, время генерации увеличим только
потому что я невнимательно читал документацию
. спасибо, ценное замечание, исправил.
кстати, если хочется использовать php шаблоны, то это уже скоро будет хорошей идеей. мы с коллегой бились лбом о проблему более удачного синтаксиса, особенно блочные функции как в smarty и т.д. придумали один костыль, который подойдет не только для шаблонизаторов. сейчас коллега его кодирует, идею в общих чертах я выложу, возможно, частично реализацию. способ спорный, но стал для нас золотой серединой.
я сейчас пытаюсь шаблонизаторы изучать, потом будет mvc, тк. запутался как лучше строить архитектуру сайта.
это хорошо, что запутался, значит уже знаешь больше одного варианта. а вот с mvc всё плохо, практически нет примеров фреймворков, которые действительно соответствуют парадигме. вот те же шаблоны используют вместо полноценной функциональной вьюхи. mvc — это скорее попсятина, понимать которую следует — разделяй компоненты в соотетствии с функционалом. я использую model (ORM), view (Smarty+плагины), front controller, классы для списков и форм, компонентный подход или виджеты. в Seagull на котором я многому научился юзаются цепочки с пре и пост фильтрами, в Zend Framework появились ActinStack. Ищи как проще и удобнее для тебя.
спасибо
да не важно, соответствует парадигме или нет.
главное что архитектура получается явной, открытой, расширяемой.
для большого приложения это очень важно. да и самому приятно
ты на первом месте
подправил, а то урл был слишком длинным (AmdY)