Я смотрю есть люди которые заинтересовались моим первым шаблонизотором хотя я его написал просто от нефиг делать и чтобы потренероваться решил создать тему посвешённую ему Шаблозитор назван Дружба =)) потому что его синтаксис представляет нечто среднее между натив пхп и смарти, короче в честь дружбы сторонником шаблонизаторов и их противников, и вообще СССР Фореве! Да код немного кривой, но это мой первый динамический шаблонизатор вот оно! PHP: <? /* --------------------------------------- Script - Шаблонизатор "Дружба" --------------------------------------- Coded - By Mr.M.I.T. --------------------------------------- */ <? class tpl { public static $tpldir,$cachedir,$cachetime; private $data,$vars,$whoreplace,$replacer,$result; function __construct() { if (!self::$tpldir) $this->error("Ошибка: Не указана папка с шаблонами"); if (!self::$cachedir) $this->error("Ошибка: Не указана папка для кеширования шаблонов"); } function error($msg) { trigger_error($msg,E_USER_ERROR); } // Записывает переменную // $name может быть массивом function set($name,$value=0) { if (is_array($name) && count($name)) { foreach($name as $key=>$val) { $this->vars[$key]=$val; } } else if (!is_array($name)){ $this->vars[$name]=$value; }else { $this->error("Ошибка: Не указано значение переменной"); } } // Шаблоном может быть строка // но тогда никакого кеширования не будет function loadStr($str) { $this->data=$str; $this->compiler(); return $this->result; } // возвращает результат парсинга // $tpl название шаболона function load($tpl) { if(!$this->is_cached($tpl)) { $fp=file_get_contents(self::$tpldir.'/'.$tpl); if ($fp) { $fp=get_magic_quotes_gpc()?stripslashes($fp):$fp; $this->data=$fp; $this->compiler(); $this->savecache($tpl); }else { $this->error("Ошибка: Шаблон $tpl не найден"); } }else { $this->compilecache($tpl); } return $this->result; } // Очищает переменные, $var может быть массивом function clear($var) { if (!is_array($var)) { if ($this->vars[$var]) unset($this->vars[$var]); }else { for($i=0,$c=count($var);$i<$c;$i++) { if ($this->vars[$var[$i]]) unset($this->vars[$var[$i]]); } } } // достаёт шаблон из кеша private function compilecache($tpl) { @ob_start(); extract($this->vars); include self::$cachedir."/".md5($tpl).".tpl.php"; $this->result=ob_get_contents(); ob_clean(); } // проверяет есть ли шаблон в кеше private function is_cached($tpl) { $dir=self::$cachedir."/".md5($tpl).".tpl.php"; if(file_exists($dir)) { if (filemtime($dir)+self::$cachetime>=time()) { return true; }else { unlink($dir); } } return false; } // компилятор private function compiler() { $sys=$this->parseSys(); for($i=0,$c=count($sys);$i<$c;$i++) { $this->whoreplace[]="{".$sys[$i]."}"; switch($this->TypeStr($sys[$i])) { case"func": $this->parseFunc($sys[$i]); break; case"var": $this->parseVar($sys[$i]); break; case"closed": $this->parseClosed(); break; case"else": $this->parseElse(); break; case false: $this->error("Неизвестный параметр {{$sys[$i]}}"); break; default: $this->parseSpec($sys[$i]); } } $this->data=str_replace($this->whoreplace,$this->replacer,$this->data); @ob_start(); extract($this->vars); eval("?".">".$this->data."<?"); $this->result=ob_get_contents(); ob_clean(); } // сохраняет шаблон в кеш private function savecache($tpl) { $dir=self::$cachedir."/".md5($tpl).".tpl.php"; file_put_contents($dir,$this->data); return true; } // список функция которые сами выводят результат, короче функции к которым не надо дописывать echo private function getPrinFunc() { return array( "print_r", "print", "echo", "var_dump", "var_export", "eval", // пцц =)) "include", "unset", "preg_match_all", "preg_match", "die", ); } private function parseFunc($f) { preg_match("#(?<!\/)([\w]+)[\s]*\((.+)\)#iU",$f,$fn); $bz=preg_match('#\$([\w]+)\=#i',$f); if ($bz || in_array(strtolower($fn[1]),$this->getPrinFunc())) $this->replacer[]="<?$f;?>"; else $this->replacer[]="<? echo $f;?>"; } private function parseVar($v) { $cmd=preg_match('#\$([\w]+)(.*?)(\=|\+|\-)#i',$v); if(!$cmd) $this->replacer[]="<? echo $v;?>"; else $this->replacer[]="<?$v;?>"; } // список строк, к которым есть свои парсеры private function getUnMatch() { return array("else"); } private function parseSpec($str) { $this->replacer[]="<?$str{?>"; } private function parseClosed() { $this->replacer[]="<?}?>"; } private function parseElse() { $this->replacer[]="<?}else{?>"; } // возвращает типы строк private function TypeStr($str) { if (in_array($str,$this->getUnMatch())) return $str; if (preg_match("#(?<!\/)([\w]+)[\s]*\((.+)\)#iU",$str,$par)) { if(!in_array($par[1],$this->getClosed())) return 'func'; else return $par[1]; } if (preg_match("#(?<=\/)([\w]+)#i",$str,$par)) return 'closed'; if (preg_match('#\$[\w]+#i',$str)) return 'var'; return false; } // функции к которым нужно дописывать фигурные скобки private function getClosed() { return array( "foreach", "if", "for", "while", ); } // возвращает строки для обработки private function parseSys() { preg_match_all("#{(.+?)}#i",$this->data,$res); return $res[1]; } } tpl::$tpldir='tpl'; // папка с шаблонами tpl::$cachedir="ctpl"; // папка с откомпилированными шаблонами tpl::$cachetime=60; // время обновления кеша $tpl=new tpl(); $tpl->set(array("arr"=>array("key1","key2",'key3'))); $tpl->set("title","Загаловок"); print $tpl->load('tpl.tpl'); ?> листинг шаблона tpl.tpl HTML: {$title}<br> {if($arr)} {$z=0} {$array=array("123","12312","123123")} {for($i=0;$i<count($arr);$i++)} {$z++} {$arr[$i]} {if ($z!==count($arr))}<hr>{/if} <br> {/for} {foreach ($array as $key=>$val)} {$array[$key]="prefix_".$val} {/foreach} {print_r($array)} {else} =))))) {/if} // А теперь отожом! {include("db.class.php")} {db::$cnf=array("db_pass"=>'','db_host'=>'localhost','db_pref'=>'test','db_name'=>'test','db_user'=>'root')} {$db=new db()} {$row=$db->super_query("SELECT * FROM ".$db->pref."_test")} {for($i=0,$c=count($row);$i<$c;$i++)} {print_r($row)}<br> {/for} Зы. Тестил только основные возможности На выходе PHP: <? echo $title;?><br> <?if($arr){?> <?$z=0;?> <?$array=array("123","12312","123123");?> <?for($i=0;$i<count($arr);$i++){?> <?$z++;?> <? echo $arr[$i];?> <?if ($z!==count($arr)){?><hr><?}?> <br> <?}?> <?foreach ($array as $key=>$val){?> <?$array[$key]="prefix_".$val;?> <?}?> <?print_r($array);?> <?}else{?> =))))) <?}?> <?include("db.class.php");?> <?db::$cnf=array("db_pass"=>'','db_host'=>'localhost','db_pref'=>'test','db_name'=>'test','db_user'=>'root');?> <?$db=new db();?> <?$row=$db->super_query("SELECT * FROM ".$db->pref."_test");?> <?for($i=0,$c=count($row);$i<$c;$i++){?> <?print_r($row);?><br> <?}?> Комментарии будут чуть позже, когда время будет напишу, пока только пример По правде говоря, сам я врятли его буду когда-нибудь использовать...хотя как знать
Олег, блин, расскусил =)) я вообще сам использую натив и не парюсь, тем более я уже где-то писал во сколько я по скорости выиграл по сравнению со смарти...
Блин. Все бы ничего, но вот как бы теперь заставить его не обращать внимания на конструкции jquery типа ${function()} ковычки-то имеют магическое значение
Mr.M.I.T. я нашел выход: главное писать не так [js]{function()}[/js] а вот так [js]{ function }[/js] и все прокатывает. !Но компилируемые шаблоны мне оч понравились. Давно говорил, что str_replace сакс, а написать что-нить руки не доходили. Вот сейчас думаю быренько смарти порвать и все будет гут. Mr.M.I.T. спасибо, что попростому помог почувствовать прекрасный мир шаблонизаторов
Не очень хорошо, что выходит из <?php ?> много раз. Вообще, я бы советовал полностью заменить конструкции такого вида: {for($i=0;$i<count($arr);$i++)} на такой: <list resourse="arr"> </list> То есть, представление делается ближе к html. Код становится наглядней, не засоряет html, и понятней. А чтобы не выходить из интерпретатора, я бы посоветовал забить в массив все html-теги и только при их встрече делать выход. Естественно, что при этом надо учесть кучу нюансов, но тогда твой шаблонизатор поднимется на уровень вверх. ИМХО.
Kreker тут цель другая была, сделать наблонизатор максимально приближенный к синтаксису пыха а на счёт тегов была идея сделать спец. теги, и юзать дом для обработки, но эт какой-то xslt получается...