За последние 24 часа нас посетили 17999 программистов и 1657 роботов. Сейчас ищет 1571 программист ...

Пример шаблонизатора

Тема в разделе "Решения, алгоритмы", создана пользователем incognitus, 15 авг 2009.

  1. incognitus

    incognitus Активный пользователь

    С нами с:
    15 авг 2009
    Сообщения:
    3
    Симпатии:
    0
    Адрес:
    cv.ua
    Вот решил написать шаблонизатор "под себя", опыт роботы с пхп у меня небольшой потому будет интересно услышать ваши мнения и замечания, я работал с шаблонизатором Smarty и пришел к выводу что иногда надо что-то облегченное с реализацией основных функций, вот и написал такой клас... Тема много раз затрагивалась но хотел бы получить совет как лучше реализовать компиляцию и сохранение в кеш... Да и необходимо ли.

    Клас class.template.php:

    PHP:
    1.  
    2. <?php
    3.  
    4.     define("TPL_TAG", "tpl");
    5.  
    6.     /*** how to define a variable ***********************/
    7.     /*** <tpl_var name="%variable name%"> ***************/
    8.  
    9.     /*** how to define a loop ***************************/
    10.     /*** <tpl_loop name="%loop name%" *******************/
    11.     /*** <tpl_loop_var name="%loop variable name%"> *****/
    12.     /*** <tpl_loop_var> *********************************/
    13.     /*** <tpl_loop_counter> *****************************/
    14.     /*** </tpl_loop> ************************************/
    15.  
    16.     /*** how to define an if-else construction **********/
    17.     /*** <tpl_if %variable%="%value%"> ******************/
    18.     /*** <tpl_else> *************************************/
    19.     /*** </tpl_if> **************************************/
    20.  
    21.     /*** how to include a file **************************/
    22.     /*** <tpl_file name="%filename%"> *******************/
    23.  
    24.     class template
    25.     {
    26.         private $data, $vars;
    27.         private $tag_types;
    28.  
    29.         public $path="./tpl";
    30.  
    31.         public function __construct($tpl_file)
    32.         {
    33.             if(!file_exists($this->path."/".$tpl_file)) die("ERROR: MAIN TEMPLATE \"$this->path/$tpl_file\" NOT FOUND");
    34.  
    35.             $this->data = @file_get_contents($this->path."/".$tpl_file);
    36.             if(!$this->data) die("ERROR: FILE_GET_CONTENTS \"$this->path/$tpl_file\"");
    37.             $this->data=trim($this->data);
    38.             $this->tag_types=array("var", "loop", "if");
    39.             $this->vars = array();
    40.         }
    41.  
    42.         public function assign($name, $value)
    43.         {
    44.             if($name == '') die("ERROR: ASSIGN NAME=''");
    45.             $this->vars[$name]=$value;
    46.         }
    47.  
    48.         public function parse()
    49.         {
    50.             while($tpl_tag=strpos($this->data, "<".TPL_TAG."_"))
    51.             {
    52.                 $pos1=strpos($this->data, "_", $tpl_tag);
    53.                 $pos2=strpos($this->data, " ", ++$pos1);
    54.                 if(!$pos1 || !$pos2)  die("ERROR: WRONG TPL TAG");
    55.                 $tpl_type=substr($this->data, $pos1, $pos2 - $pos1);
    56.  
    57.                 if(!in_array($tpl_type, $this->tag_types)) die("ERROR: WRONG TYPE TPL TAG");
    58.  
    59.                 $pos1=$pos2;
    60.                 $pos2=strpos($this->data, "=\"", ++$pos1);
    61.                 if(!$pos2)  die("ERROR: WRONG PARAM NAME IN TPL TAG");
    62.                 $tpl_name=substr($this->data, $pos1, $pos2-$pos1);
    63.  
    64.                 $pos1=++$pos2;
    65.                 $pos2=strpos($this->data, "\">", ++$pos1);
    66.                 if(!$pos2)  die("ERROR: WRONG PARAM VALUE IN TPL TAG");
    67.                 $tpl_value=substr($this->data, $pos1, $pos2-$pos1);
    68.  
    69.                 switch($tpl_type)
    70.                 {
    71.                     case "var":
    72.                         if(isset($this->vars[$tpl_value])) {
    73.                             $this->data=str_replace("<".TPL_TAG."_var ".$tpl_name."=\"".$tpl_value."\">", $this->vars[$tpl_value], $this->data);
    74.                         }
    75.                         else {
    76.                             $tplstr="<".TPL_TAG."_var ".$tpl_name."=\"".$tpl_value."\">";
    77.                             $this->data=str_replace(array($tplstr.chr(13).chr(10), $tplstr), "", $this->data);
    78.                         }
    79.                         break;
    80.  
    81.                     case "loop":
    82.                         $pos1=strpos($this->data, "</".TPL_TAG."_loop>", $pos2)+strlen("</".TPL_TAG."_loop>");
    83.                         $pos2=$tpl_tag;
    84.                         $loop_block=substr($this->data, $pos2, $pos1-$pos2);
    85.  
    86.                         if(isset($this->vars[$tpl_value])) {
    87.                             $this->data=str_replace($loop_block, $this->process_loop($loop_block, $this->vars[$tpl_value]), $this->data);
    88.                         }
    89.                         else {
    90.                             $this->data=str_replace(array($loop_block.chr(13).chr(10), $loop_block), "", $this->data);
    91.                         }
    92.                         break;
    93.  
    94.                     case "if":
    95.                         $pos1=strpos($this->data, "</".TPL_TAG."_if>", $pos2)+strlen("</".TPL_TAG."_if>");
    96.                         $pos2=$tpl_tag;
    97.                         $if_block=substr($this->data, $pos2, $pos1-$pos2);
    98.  
    99.                         if(isset($this->vars[$tpl_name])) {
    100.                             $this->data=str_replace($if_block, $this->process_if($if_block, array($tpl_name=>$this->vars[$tpl_name])), $this->data);
    101.                         }
    102.                         else {
    103.                             $this->data=str_replace(array($if_block.chr(13).chr(10), $if_block), "", $this->data);
    104.                         }
    105.                         break;
    106.  
    107.                     default:
    108.                         break;
    109.                 }
    110.             }
    111.         }
    112.  
    113.         private function process_loop($loop_block, $data)
    114.         {
    115.             $pos1=strpos($loop_block, ">");
    116.             $pos1++;
    117.             $pos2=strpos($loop_block, "</".TPL_TAG."_loop>");
    118.             $tpl=substr($loop_block, $pos1, $pos2-$pos1);
    119.             $r="";
    120.  
    121.             foreach($data as $i=>$item)
    122.             {
    123.                 if(is_array($item)) {
    124.                     $temp=$tpl;
    125.                     $temp=str_replace("<".TPL_TAG."_loop_counter>", $i+1, $temp);
    126.                     foreach($item as $k=>$v)
    127.                     {
    128.                         $temp=str_replace("<".TPL_TAG."_loop_var name=\"$k\">", $v, $temp);
    129.                     }
    130.                     $r.=trim($temp);
    131.                 }
    132.                 else {
    133.                     $temp=$tpl;
    134.                     $temp=str_replace("<".TPL_TAG."_loop_counter>", $i+1, $temp);
    135.                     $r.=trim(str_replace("<".TPL_TAG."_loop_var>", $item, $temp));
    136.                 }
    137.             }
    138.  
    139.             return trim($r);
    140.         }
    141.  
    142.         private function process_if($if_block, $data)
    143.         {
    144.             if(strstr($if_block, key($data)."=\"".current($data)."\"")) {
    145.                 $pos1=strpos($if_block, ">", 0);
    146.                 $pos1++;
    147.                 $pos2=(strstr($if_block, "<".TPL_TAG."_else>")) ? strpos($if_block, "<".TPL_TAG."_else>", $pos1) : strpos($if_block, "</".TPL_TAG."_if>", $pos1);
    148.                 $r=trim(substr($if_block, $pos1, $pos2-$pos1));
    149.             }
    150.             else if(strstr($if_block, "<".TPL_TAG."_else>")) {
    151.                 $pos1=strpos($if_block, "<".TPL_TAG."_else>")+strlen("<".TPL_TAG."_else>");
    152.                 $pos2=strpos($if_block, "</".TPL_TAG."_if>", $pos1);
    153.                 $r=trim(substr($if_block, $pos1, $pos2-$pos1));
    154.             }
    155.             return $r;
    156.         }
    157.  
    158.         public function inc_files()
    159.         {
    160.             while($inc_file_pos = strpos($this->data, "<".TPL_TAG."_file name=\""))
    161.             {
    162.                 $pos1=$inc_file_pos+strlen("<".TPL_TAG."_file name=\"");
    163.                 $pos2=strpos($this->data, "\"", $pos1);
    164.                 if(!$pos2) die("ERROR: WRONG TAG INC_FILES()");
    165.  
    166.                 $filename=substr($this->data, $pos1, $pos2-$pos1);
    167.                 if(!file_exists($this->path."/".$filename)) die("ERROR: INC TEMPLATE \"$this->path/$filename\" NOT FOUND");
    168.  
    169.                 $inc_data=@file_get_contents($this->path."/".$filename);
    170.                 if(!$inc_data) die("ERROR: INC FILE_GET_CONTENTS \"$this->path/$tpl_file\"");
    171.                 $inc_data=trim($inc_data);
    172.                 $this->data=str_replace("<".TPL_TAG."_file name=\"$filename\">", $inc_data, $this->data);
    173.             }
    174.         }
    175.  
    176.         public function print_html()
    177.         {
    178.             echo $this->data;
    179.         }
    180.  
    181.         public function data()
    182.         {
    183.             return $this->data;
    184.         }
    185.     }
    186. ?>
    187.  
    Пример шаблонов - основного и например инклуда в основной:

    file.tpl

    HTML:
    1.  
    2.     <title></title>
    3. </head>
    4.     <h2>
    5.         <tpl_var name="title">
    6.     </h2>
    7.     <tpl_var name="body"><br>
    8.     <br><i>users & ids</i> :<br>
    9.     <tpl_loop name="user_id">
    10.         <tpl_loop_counter>&nbsp;&nbsp;<tpl_loop_var name="user"> :: <tpl_loop_var name="id"><br>
    11.     </tpl_loop>
    12.     <tpl_if is_error="true">
    13.         <div style="border: 1px solid red;padding: 20px;width: 50px;height: 40px;"><b>IS</b> ERROR</div>
    14.     <tpl_else>
    15.         <div style="border: 1px solid blue;padding: 20px;width: 50px;height: 40px;"><b>NO</b> ERRORS</div>
    16.     </tpl_if>
    17.     <tpl_file name="inc.tpl">
    18. </body>
    19. </html>
    20.  
    inc.tpl

    HTML:
    1.  
    2. <tr>
    3.     <td><i>inc_var1</i> =</td><td><tpl_var name="inc_var1"></td>
    4. </tr>
    5. <tr>
    6.     <td><i>inc_var2</i> =</td><td><tpl_var name="inc_var2"></td>
    7. </tr>
    8.  
    Пример работы:

    PHP:
    1.  
    2. <?php
    3.     include "class.template.php";
    4.  
    5.         $tpl = new template("file.tpl");
    6.         $tpl->assign("title", "Hello, World!");
    7.         $tpl->assign("body", "text in the block 'body'");
    8.         $tpl->assign("is_error", "false");
    9.         $tpl->assign("user_id", array(array("user"=>"user19", "id"=>"112"), array("user"=>"user3", "id"=>"22"), array("user"=>"user71", "id"=>"32")));
    10.         $tpl->assign("inc_var1", "inc_var_value1");
    11.         $tpl->assign("inc_var2", "inc_var_value2");
    12.  
    13.         $tpl->inc_files();
    14.         $tpl->parse();
    15.         $tpl->print_html();
    16.         #echo $tpl->data();
    17.         $tpl=NULL;
    18. ?>
    19.  
     
  2. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    Код не очень внимательно посмотрел, может, посмотрю позже, но, по-моему, присутствует избыточность:
    HTML:
    1. <tpl_var name="inc_var2">
    даже на нейтив-шаблонизаторе выглядит красивше:
    PHP:
    1. <?=$inc_var2?>
    Плюс, подсветка не очень корректно будет работать, да и ИДЕ с ума сходить будет:
    HTML:
    1. <a href="<tpl_var name="aHref">"><tpl_var name="aTitle"></a>
    Плюс — сливается все в один цвет при подсветке, так как, что синтаксис шаблонизатора, что синтаксис шаблонизирумого языка — одинаков.

    Мне более нравится идея совмещения <!-- BLOCK --> и {VAR} — синтаксис подсветился серым (так,как основа синтаксиса — хтмл-комментарии, которые практически не используются при верстке), а все переменные не разрушают структуру кода (иде нормально к ним относятся, так как воспринимают, как обычный текст), и очень легко печатать. Сравни:

    Код (Text):
    1. <tpl_var name="inc_var2">
    2. {inc_var2}
    Но изобретение своих велосипедов — дело благородное и правильное.
     
  3. kostyl

    kostyl Guest

    Использование знаков < > в шаблоне это не правильно. Эти штуки зарезервированы для HTML, если говорить вообщем. Поэтому, лучше подобрать другие признаки.
     
  4. incognitus

    incognitus Активный пользователь

    С нами с:
    15 авг 2009
    Сообщения:
    3
    Симпатии:
    0
    Адрес:
    cv.ua
    В принципе согласен, хотел сделать похожими на html-теги).
     
  5. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    kostyl, не совсем согласен. <!-- --> — отлично подходит для блоков.
     
  6. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    HTML:
    1.  
    2. [:loop myArray:]
    3.     <tr>
    4.         <td>[:id:]</td><td>[:title:]</td>
    5.     </tr>
    6. [:/loop:]
    7.  
    а ваще - пользователь шаблонизатора сам вправе выбирать какие именно символы использовать
    {}
    []
    {%%}
    [::]
    ...
     
  7. TheShock

    TheShock Активный пользователь

    С нами с:
    30 май 2009
    Сообщения:
    1.255
    Симпатии:
    0
    Адрес:
    Київ
    согласен. в настройках шаблона указать:
    PHP:
    1. <?
    2. $var = '{*}';
    3. $block = '((*))';
    где звездочка — сам код.
     
  8. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    ну как видно у меня [::] для всего: переменные, циклы, условия.

    а блок - это что?
     
  9. kostyl

    kostyl Guest

    да "<!--" отлично подходит. Я имел в виду "<"
     
  10. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    он не компилируемый?
    если так - то он зло
     
  11. incognitus

    incognitus Активный пользователь

    С нами с:
    15 авг 2009
    Сообщения:
    3
    Симпатии:
    0
    Адрес:
    cv.ua
    Посоветуйте пожалуйста как можно реализовать кеш и компиляцию..
     
  12. kostyl

    kostyl Guest

    Поищи в этом разделе полно информации
     
  13. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
  14. Вообще, я знаю как минимум один интересный шаблонизатор, замешанный на HTML — в phpc
     
  15. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    флоппик
    xslt почти
     
  16. silverworld

    silverworld Активный пользователь

    С нами с:
    1 авг 2009
    Сообщения:
    10
    Симпатии:
    0
    Адрес:
    Ðîññèÿ
    Ïðèìåð øàáëîíèçàòîðà

    Ôóóóóó...