Есть следующий код. Есть ли идеи по оптимизации. PHP: $data=<<<HEREDOC [foreach {f_arr}] {f_val:name}<br /> <b>{f_val:value}</b> <br /><br /> [/foreach] HEREDOC; $vars['foreach']['arr'][]=array('name'=>'my1','value'=>'jon'); $vars['foreach']['arr'][]=array('name'=>'my2','value'=>'smit'); $vars['foreach']['arr'][]=array('name'=>'my3','value'=>'anjil'); $vars['foreach']['arr'][]=array('name'=>'my4','value'=>'demon'); $vars['foreach']['arr'][]=array('name'=>'my5','value'=>'tokar'); preg_match_all('/\[foreach {f_(.+?)}](.+?)\[\/foreach\]/is', $data, $parr); if(isset($parr)) { $tmpd=''; foreach ($parr[0] as $k => $v) { foreach ($vars['foreach'][$parr[1][$k]] as $tmp) { //print_r($tmp); $work=$parr[2][$k]; preg_match_all('/{f_(\S+?):(\S+?)}/i', $data, $farr); $num_var=count($farr[2]); for($i=0;$i<$num_var;$i++) $work=str_replace("{f_{$farr[1][0]}:{$farr[2][$i]}}",$tmp[$farr[2][$i]],$work); $tmpd.=$work; } $data = str_replace($v, $tmpd,$data ); } } echo $data; у меня только одна идея. заменить тут str_replace PHP: for($i=0;$i<$num_var;$i++) $work=str_replace("{f_{$farr[1][0]}:{$farr[2][$i]}}",$tmp[$farr[2][$i]],$work); на preg_replace но чето немогу некак составить регулярку. Да и надо ли? Еще думаю можно избавиться от временных переменных. но тоже не-могу придумать нечего.
хотя можно так =)) PHP: <? $data=<<<HEREDOC [foreach item=var key=key value=val] <b>{key}</b> <br> [foreach item=val key=k value=v] {k}=>{v}<br> [/foreach] <br /><br /> [/foreach] HEREDOC; function getattr($str) { preg_match_all("#([^\[\]\s]+)=([^\[\]\s]+)#i",$str,$res); $attr=array(); for($i=0,$c=count($res[1]);$i<$c;$i++) { $attr[$res[1][$i]]=$res[2][$i]; } return $attr; } $vars=array("var"=>array("key1"=>array("key1"=>"val1","key2"=>"val2"),"key2"=>array("key1"=>"val1","key2"=>"val2"))); $compile=''; $compile=str_replace("{","<?=\$vars['",$data); $compile=str_replace("}","'];?".">",$compile); $compile=str_replace("[/foreach]","<?}?>",$compile); preg_match_all("#\[foreach(.+?)\]#is",$compile,$res); $who=array(); $replace=array(); for($i=0,$c=count($res[0]);$i<$c;$i++) { $who[]=$res[0][$i]; $attr=getattr($res[0][$i]); $replace[]="<?foreach(\$vars['{$attr['item']}'] as \$vars['{$attr['key']}']=>\$vars['{$attr['value']}']){?>"; } $compile=str_replace($who,$replace,$compile); eval("?".">".$compile."<?"); ?>
Объясните неразумному (немодному ), это чО: Код (Text): $data=<<<HEREDOC [foreach item=var key=key value=val] <b>{key}</b> <br> [foreach item=val key=k value=v] {k}=>{v}<br> [/foreach] <br /><br /> [/foreach] HEREDOC; у меня даже не "компайлится"
Mr.M.I.T. дошло, пробела в закрывающем HEREDOC не должно быть)) очуметь. Спасибо. [off]если в шапке была идея сделать парсер темплейтов с циклами, то идея по организации работы мне ваще не нравится.[/off]
наверно тем что вы пытаетесь имитировать циклы и а не компилировать свои шаблоны в натив пхп представление Зы. Ещё раз, шаблонизаторы это зло, используйте натив пхп, ну или по крайней мере пиши синтаксис шаблонов как можно ближе к пхпшному например Код (Text): {foreach($arr as $key=>$val)} {$key}=>{$val}<br> {$val=htmlspecialchars($val)} {$val} {/foreach} как то так
А eval для обработки темплейтах это нормально(и по скорости работает быстрее чем то-что я писал?). Если да то сделать именно на натив не проблема.
alien К сожалению, не могу точно описать. Так как еще НЕ думал о написании такого парсера, да думаю и не буду. Но если прямо на ходу то примерно вижу так (далее поток сознания, сорри если чего не понятно). Будут интерфейсы (с методами вывода), будут классы ( по типам , например класс описывающий foreach или array). Класс foreach имеющий аттрибуты (которые тоже классы). Будет дерево из таких классов в результате парсов (может переработка в xml). Потом будет обратная сборка с подставлением значений (с пробегом - может по дереву) с использованием методов реализованных интерфейса. А тут я вижу решение в лоб. Не масштабируемое, неудобное и тд. Но допускаю, что абсолютно раочее. Сорри, если чО
вот оно! PHP: <? 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); } function set($name=0,$value=0) { if (is_array($name) && !empty($name)) { foreach($name as $key=>$val) { $this->vars[$key]=$val; } } else if (!empty($name) && (!empty($value) || $value==0 || $value==false)){ $this->vars[$name]=$value; } } function loadStr($str) { $this->data=$str; $this->compiler(); return $this->result; } 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; } private function compilecache($tpl) { @ob_start(); 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(); 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; } private function getPrinFunc() { return array( "print_r", "print", "echo", "var_dump", "var_export", "eval", // пцц =)) "include", ); } private function parseFunc($f) { preg_match("#(?<!\/)([\w]+)[\s]*\((.+)\)#iU",$f,$fn); $bz=preg_match('#\$([\w]+)\=#i',$f); $f=preg_replace('#(?<!\:\:)\$([\w]+)#i',"\$this->vars['\\1']",$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); $v=preg_replace('#\$([\w]+)#i',"\$this->vars['\\1']",$v); if(!$cmd) $this->replacer[]="<? echo $v;?>"; else $this->replacer[]="<?$v;?>"; } private function getUnMatch() { return array("else"); } private function parseSpec($str) { $str=preg_replace('#\$([\w]+)#i',"\$this->vars['\\1']",$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", ); } private function parseSys() { preg_match_all("#{(.+?)}#is",$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'))); print $tpl->load('tpl.tpl'); ?> листинг шаблона tpl.tpl HTML: {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: <?if($this->vars['arr']){?> <?$this->vars['z']=0;?> <?$this->vars['array']=array("123","12312","123123");?> <?for($this->vars['i']=0;$this->vars['i']<count($this->vars['arr']);$this->vars['i']++){?> <?$this->vars['z']++;?> <? echo $this->vars['arr'][$this->vars['i']];?> <?if ($this->vars['z']!==count($this->vars['arr'])){?><hr><?}?> <br> <?}?> <?foreach ($this->vars['array'] as $this->vars['key']=>$this->vars['val']){?> <?$this->vars['array'][$this->vars['key']]="prefix_".$this->vars['val'];?> <?}?> <?print_r($this->vars['array']);?> <?}else{?> =))))) <?}?> <?include("db.class.php");?> <?db::$cnf=array("db_pass"=>'','db_host'=>'localhost','db_pref'=>'test','db_name'=>'test','db_user'=>'root');?> <?$this->vars['db']=new db();?> <?$this->vars['row']=$this->vars['db']->super_query("SELECT * FROM ".$this->vars['db']->pref."_test");?> <?for($this->vars['i']=0,$this->vars['c']=count($this->vars['row']);$this->vars['i']<$this->vars['c'];$this->vars['i']++){?> <?print_r($this->vars['row']);?><br> <?}?>
Блин МЕГА. Супер. Слушай ты не против если твой шаблонизатор заюзаю. Просто очуметь. то-что нужно. Это лучше всего что я видел. Смарти мне не нравиться(вообще, не просите объяснять просто не нравиться) Еще протестирую на скорость работы. Если будет неплохая то буду юзать спс.
alien да мне не жалко =)) делать нечего вот и написал, только я его почти не тестил, если что говори, буду исправлять =)
Ок. Буду тестить. еще print $tpl->load('tpl.tpl'); думаю сразу выводить не самое лучшая идея. Что нибудь придумаю по этому поводу.