PHP: <?php $view = new Template('./1.tpl',1,'.'); $view -> var = new Template('./2.tpl',1,'.'); в кэше 1.tpl и так оказывается содержимое 2.tpl. В связи с этим вопрос - зачем вообще когда-либо кэшировать подшаблоны?
Так я не понял, вопрос в хранении или нет? =)) В смысле то, что константные значения принято делать в верхнем регистре? Где посмотреть? 1)Либо надо от каждой считать хэш и идти в глубь массивов, 2)Либо не идти в глубь массивов, а превращать их в строку (serialize, jspn_encode и т.д.) и тогда возникает вопрос зачем так сложно, когда можно сразу сериализовать весь объект. 3)Либо надо удалять/заменять подшаблоны. Я прошел по второму пути. А какой выигрыш нам даст глубинный расчет хэша подшаблонов? 1) Не хочешь не кешируй: PHP: <?php $view = new Template('./1.tpl',1,'.'); $view -> var = new Template('./2.tpl',false); или PHP: <?php $vf["tpl"]["needCache"]=false; $view = new Template('./1.tpl',true,'.'); $view -> var = new Template('./2.tpl'); 2) Есть шаблон с двумя подшаблонами. При изменении одного подшаблона пересчитывается один подшаблон и главный шаблон, а второй подшаблон берется из кеша. 3) Есть шаблон который используется в нескольких других шаблонах которые не кешируются.
Mr.M.I.T. Отдельный класс/объект реестра вместо массива? Инкапсуляция данных против небольшого увеличения сложности. Возможно это имеет смысл. Спасибо за совет.
Если использовать сериализованые массивы, то при unserialize будут заново создаваться экземпляры классов, быстрее собрать массивы обычных переменных и их использовать )))
Причем тут глубинный расчет хэша? Выигрыш будет в том, что у нас не будет левых методов и каждый объект сам контролирует свое состояние. Дело в том, что лично меня бы не волновало, что PHP: <?php $class1 = new stdClass $class1->a = 'a'; $class1->b = 'b'; $class2 = new stdClass $class2->b = 'b'; $class2->a = 'a'; md5(serialize($class1)) != md5(serialize($class2)); Вам захотелось контролировать эти ситуации - ради бога. Только не надо забирать данные у подшаблонов и хешировать их. Мы говорим ему - сделай. А не - дай нам данные, мы сделаем. Скажи ему - "дай свой хеш". И все. В твоем случае хеш подшаблонов вообще не используется - ты заставляешь их себя упорядочивать - это вполне вариант.
Simpliest Ты имеешь в виду нечто вроде такого: PHP: <?php public function hashCode(){ $hash = 0; $vars=$this->vars; foreach($vars as $key=>$var){ if ($var instanceof Template){ $vars[$key] = $var->hashCode(); } } $hash=md5(serialize($vars)); return $hash; } ? [vs] Ага. Только придется решать вопросы: как контролировать разрастание количества файлов кеша (чистить руками или создавать некий класс "манагер кеша") и как ловить изменение шаблона (программно или ручками удалять хеш)
Ух... как мне это не нравится ну как вариант. меня больше устраивает просто Код (Text): md5(serialize($this)); По времени последнего доступа.
Можно именовать файл кэша так PHP: md5($path).md5(ыукшфдшяу($this)) потом делать glob по первой части имени, если есть - сравнивать вторую часть с хэшем текущего объекта, если совпадает - грузить, если нет - удалять файл и компилить...
Simpliest Мы достаточно долго обсуждали, что подшаблоны должны выдавать свой хеш вместо переменных вот я и пытался понять как это согласуется с моим классом и куда это всунуть. Я, наверное, далеко не сразу бы увидел такую мысль... но вопрос больше в том кто и как будет убирать лишние файлы, чем какие именно файлы удалять. [vs] 1) Идея как раз в том, что можно хранить несколько часто используемых кешей одного шаблона. 2) Нафига md5($path), когда у меня используется basename($this->path, ".tpl") и делай glob по нему, если очень надо. Опять же админ при взгляде на файлы кеша быстро поймет какой файл от какого шаблона. 3) По-моему это не совсем дело шаблона... Точнее я пока не вижу хорошего способа прикрепить задачу очистки от старых кешей к классу Template.
если только вписать в имя файла хэши подшаблонов, потом разбивать это имя на подстроки по 32 символа и проверять хэши )) тогда возникнет ошибка, если грубо говоря один шаблон называется b, а второй - ba.
Simpliest идею вроде понял. Буду думать. [vs] Ошибка возникнет, если есть два шаблона b.tpl, у которых одинаковый набор переменных, но разная внутренность и то у них будет разный хеш, т.к. в serialize($this) включается свойство $path.
я вот подумал, было бы проще, если бы разработчики PHP (дабы избавить многих от изобретения велосипеда) сделали режим трансляции файлов с расширением *.tpl, при котором транслятор "понимал" бы только ограниченный набор функций, но достаточный для программной вёрстки веб-страниц...
Решил развить идею пассивного шаблонизатора. Это конечно не FastTemplate, но основная цель - разделение PHP и HTML достигнута. const.php: PHP: <?php // cms-lite (c) =) define( "__START__", microtime(true)); define( "__QUERY__", intval($_SERVER["QUERY_STRING"]) ); define( "__tpl_path__" , "./%s.tpl" ); define( "__chr_open__" , "{"); define( "__chr_close__", "}"); define( "__begin_open__" , "{begin "); define( "__begin_close__", "}"); define( "__end_open__" , "{end "); define( "__end_close__", "}"); define( "__str_site__" , "Мой сайт" ); define( "__str_submit__" , "Далее"); define( "__err_tpl_not_found__", "<b>Ошибка: </b>шаблон %s не найден" ); define( "__err_block_not_found__", "<b>Ошибка: </b>блок %s не найден" ); ?> globals.php: PHP: <?php $arrNodes = array( 0=>"Главная", 1=>"Пользователи", 2=>"Регистрация", 3=>"Вход", 4=>"Выход", 5=>"Контакты", 6=>"Добавить контакт", 7=>"Удалить контакт", 8=>"Форумы", ); $arrChilds = array( "root"=>array(0), 0=>array(1,8), 1=>array(2,3,4,5), 5=>array(6,7), ); ?> class.Template.php: PHP: <?php class Template{ private $_strTpl; private $_arrBlocks = array(); public function __construct($strName) { $p = sprintf(__tpl_path__,$strName); if( file_exists($p) ){ $this->_strTpl = file_get_contents($p); }else{ exit(sprintf(__err_tpl_not_found__,$strName)); } $this->_strTpl = $this->detectBlock($this->_strTpl); } private function detectBlock($strTpl){ $e1 = explode(__begin_open__, $strTpl, 2); if( sizeof($e1)<2 ){ return $strTpl; } $e2 = explode(__begin_close__, $e1[1], 2); if( sizeof($e2)<2 ){ return $strTpl; } $b = $e2[0]; $e3 = explode(__end_open__ . $b . __end_close__, $e2[1], 2); if( sizeof($e3)<2 ){ return $strTpl; } $this->_arrBlocks[$b] = $this->detectBlock($e3[0]); $s = $this->detectBlock($e3[1]); return $e1[0] . __chr_open__ . $b . __chr_close__ . $s; } public function __get($strName) { if( !isset($this->_arrBlocks[$strName]) ){ exit(sprintf(__err_block_not_found__,$strName)); } return $this->_arrBlocks[$strName]; } public function __toString() { return $this->_strTpl; } } ?> class.View.php: PHP: <?php class View{ private $_strTpl=""; private $_arrFrom=array(); private $_arrTo=array(); public function __construct($strTpl) { $this->_strTpl = $strTpl; } public function __set($strVar, $strVal) { $this->_arrFrom[$strVar] = __chr_open__ . $strVar . __chr_close__; $this->_arrTo[$strVar] = $strVal; } public function __get($strVar) { if( !isset($this->_arrTo[$strVar]) ){ $this->__set($strVar, ""); } return $this->_arrTo[$strVar]; } public function __toString() { return str_replace($this->_arrFrom,$this->_arrTo,$this->_strTpl); } } ?> И небольшой примерчик вдогонку, в котором генерируется иерархическое меню и простенькая форма. index.php: PHP: <?php error_reporting($_SERVER["SERVER_ADDR"]==="127.0.0.1" ? E_ALL : 0); include("./const.php"); include("./globals.php"); include("./class.Template.php"); include("./class.View.php"); if($_POST){ $intSelect = isset($_POST["select"]) ? intval($_POST["select"]) : 0; header("Location:/?".$intSelect); exit(); } $tpl_main = new Template("main"); $tpl_menu = new Template("menu"); $tpl_form = new Template("form"); function build_menu($i) { global $tpl_menu,$arrNodes,$arrChilds; $menu = new View($tpl_menu); foreach( $arrChilds[$i] as $q ){ if( isset($arrChilds[$q]) ){ $b = ( $q === __QUERY__ ) ? "item3" : "item4"; }else{ $b = ( $q === __QUERY__ ) ? "item1" : "item2"; } $item = new View($tpl_menu->$b); if( $q!==__QUERY__ ){ $item->href = "/?".$q; } $item->title = $arrNodes[$q]; if( isset($arrChilds[$q]) ){ $item->menu = build_menu($q); } $menu->items .= $item; } return $menu; } $form = new View($tpl_form); $form->href = "/"; foreach( $arrNodes as $q=>$t ){ $b = ( $q===__QUERY__ ) ? "option1" : "option2"; $option = new View($tpl_form->$b); $option->value = $q; $option->title = $t; $form->options .= $option; } $form->str_submit = __str_submit__; $main = new View($tpl_main); $main->site = __str_site__; $main->title = $arrNodes[__QUERY__]; $main->menu = build_menu("root"); $main->form = $form; echo $main; echo microtime(true) - __START__; ?> main.tpl: Код (Text): <html> <head> <title>{site} - {title}</title> </head> <body> {menu} <hr> {form} </body> </html> menu.tpl: Код (Text): <ul> {begin items} {begin item1}<li>{title}{end item1} {begin item2}<li><a href="{href}">{title}</a>{end item2} {begin item3}<li>{title}{menu}{end item3} {begin item4}<li><a href="{href}">{title}</a>{menu}{end item4} {end items} </ul> form.tpl: Код (Text): <form action="{href}" method="post"> <select name="select"> {begin options} {begin option1}<option value="{value}" selected>{title}{end option1} {begin option2}<option value="{value}">{title}{end option2} {end options} </select> <br> <input type="submit" value="{str_submit}"> </form>
HTML: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel="stylesheet" href="default.css" type="text/css"> <script type="text/javascript" src="jquery.min.js"></script> <script type="text/javascript" src="KCZ.js"></script> <title></title> </head> <body onload="Update('content', document.getElementById('content'));"> <table width="100%" height="100%" cellpadding="0" cellspacing="0" border="0"> <tr height="80px" onclick="Update('content', document.getElementById('content'), '<?php echo KCZ_Escape::Url($Data->MainPageUrl)?>');" class="header"> <td align="center"> <div id="header"> </div> </td> </tr> <tr> <td> <div id="menu"> <?php echo $Data->MainMenu?> </div> </td> </tr> <tr valign="top" height="100%"> <td> <div id="content"> <?php echo KCZ_Escape::Html($Data->OffJavaScript)?></div> </div> </td> </tr> <tr> <td> <div id="footer"> </div> <div id="debug"> </div> </td> </tr> </table> </body> </html> ))