ФорумПрограммированиеPHP для идиотов → Снова парсер шаблонов

Снова парсер шаблонов

  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 9:32

    А куда нам без них!

    Выношу на суд общественности мой вариант. Возможностей немного, необходимый минимум:
    - подстановка значений
    - подстановка значений с экранированием. (типа защита от внедренного кода)
    - подстановка по индексу массива, размерность любая.

    Жду злобных комментариев.

    Сначала шаблон example.tpl:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru" dir="ltr">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     <title><!– title –></title>
    </head>

    <body>

    <p>Message: <!– message –></p>

    <p>Code: <!– code –></p>

    <p>Escaped code: <!– @code –></p>

    Array access:
    <ul>
    <li>xarr['a']: "<!– xarr:a –>" - element</li>
    <li>esc(xarr['a']): "<!– @xarr:a –>" - escaped element</li>
    <li>xarr['b']['r']: "<!– xarrbr –>" - multidimentional</li>
    <li>xarr['b'][12]: "<!– xarrb12 –>" - multidimentional, int key</li>
    <li>xarr['c'][8]: "<!– xarr:c:x –>" - (wrong index)</li>
    <li>xarr['d'][1]: "<!– xarr:d:1 –>" - array d is reference</li>
    </ul>

    </body>
    </html>


    Теперь сам парсер example.php

    <?php

    $arrByRef = array('alpha', '<b>b</b>eta', 'gamma');

    $data = array(
    'title' => 'The Example page',
    'message' => 'Some text',
    'code' => 'The <b>bold</b> text',
    'xarr' => array(
    'a' => 'AAA<u>UUU</u>BBB',
    'b' => array(
    'q' => 'B10',
    'r' => 'B11',
    12 => 'B12'),
    'd' => &$arrByRef)
    );


    function htmlescape($str)
    {
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
    }


    function parseTemplate(&$data, $file)
    {
    // template is NOT php-script, read it as plain text
    $text = file_get_contents($file);
    // then if data provided, substitute placeholders
    if (!is_null($data) && count($data))
    {
    // split to parts divided by "<!– key –>"
    $arr = preg_split('/(<!–.*–>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
    // … if any, process substitutions
    if (count($arr) > 1)
    {
    $text = '';
    foreach ($arr as $clause)
    {
    if (substr($clause, 0, 4) == '<!–')
    {
    // strip "<!–" and "–>"
    $key = trim(substr($clause, 4, -3));
    $escape = FALSE;
    $success = TRUE;

    if ($key{0} == '@')
    {
    $key = substr($key, 1);
    $escape = TRUE;
    }

    if (strpos($key, ':') !== FALSE)
    {
    $keys = explode(':', $key);
    $d =& $data;
    foreach ($keys as $key)
    {
    if (isset($d[$key]))
    $d = &$d[$key]; // iterate like chained list
    else
    {
    $success = FALSE;
    break;
    }
    }
    if ($success)
    $clause = $d;
    }
    else
    {
    if (isset($data[$key]))
    $clause = $data[$key];
    }

    if ($success && $escape)
    $clause = htmlescape($clause);

    }

    $text .= $clause;
    }
    }
    }

    echo $text;
    }

    parseTemplate($data, './example.tpl');


    Update: ниже есть обновлённый вариант http://pyha.ru/forum/topic/2013.msg34213#msg34213

    Update N: http://pyha.ru/forum/topic/2013.msg36109#msg36109
    if-elseif-else, foreach, компиляция в PHP, модификаторы по типу {:var|str_repeat,3|strtolower}
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 9:33, спустя 1 минуту 47 секунд

    Упс! Чего-то здешний парсер php подглючивает. Ну, думаю, разберетесь что было в оригинале!
    screenshot результата
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 10:24, спустя 50 минут 51 секунду

    наговнякал новую версию с возможностью инклудить под-шаблоны. смотри вложение.


    <!– include header –>


    вот бы еще foreach $array добавить и можно остановиться на этом
    ιιlllιlllι унц-унц
  • Trej Gun

    Сообщения: 5305 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 12:39, спустя 2 часа 15 минут 9 секунд

    начал блевать на строке
    preg_split('/(<!–.*–>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
  • Lirck

    Сообщения: 1658 Репутация: N Группа: Джедаи

    Spritz 23 февраля 2009 г. 13:10, спустя 30 минут 22 секунды


    наговнякал новую версию с возможностью инклудить под-шаблоны. смотри вложение.


    <!– include header –>


    вот бы еще foreach $array добавить и можно остановиться на этом


    разрабы смарти не смогли остановится, уверен что у тебя получится??)))
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 13:17, спустя 7 минут 38 секунд

    а чо смарти теги не понравились?
    {}

    <!– –> - минимум не локонично. 7 букаф ради вывода переменной, ебал я такой вывод, проще уж <?=$var?> - всего 5. смарти и удобен своей лаконичностью :) + я так понимаю, что твой - не компилирует в пхп файла файлы шаблонов, а имхо это не есть гут для производительности :)
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 15:15, спустя 1 час 57 минут 51 секунду

    Объясняю: я не собираюсь конкурировать со смарти. Найдется масса микро-задач, где приятней иметь парсер из 100 строк. Для малых задач Smarty — это 300K бесполезного груза. Кто-то блюет от единственного regexp, а меня мутит от мопеда с корабельным двигателем.
    Пацаны, вы что правда думаете, что есть мега-решение на все случаи?

    phpdude, я вообщето обычно пользую нативный "шаблонизатор" типа:

    echo <<<EOT
    <tr>
    <td class="left">{$username}</td> <td class="right">{$message}</td>
    </tr>
    EOF;

    наглядно и эффективно. Но вот понадобилось отпимизировать одну чужую задачку…  
    Почему <!– var –> ?
    1. Этот код родной для редактора с подсветкой синтаксиса HTML;
    2. Неинициированная var в моем примере оставляет в тексте исходный код как html-комментарий. Мне так показалось удобно. Я могу сделать шаблон с "лишними" тегами. Например ставлю <!– include footer –> Футера пока нет, разметка не страдает, но я вижу в теле страницы этот фрагмент. По мере роста приложения теги наполняются содержанием.

    Перейти на {var} проще простого.
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 15:24, спустя 8 минут 30 секунд

    <!–> сам так юзал смарти сначала, потом отказался .. ио слишком громадный хтмл остается)) а идея да, прикольная
    Сапожник без сапог
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 15:28, спустя 4 минуты 14 секунд

    слушай, а нахуй preg_split??
    чем прег мач олл не устрол? или я чего то непонимаю
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 15:30, спустя 2 минуты 10 секунд

    imho недопонимаешь.
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 15:32, спустя 1 минуту 42 секунды

    я поверхностно глянул)
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 15:38, спустя 5 минут 58 секунд

    не только ты. это добрая традиция — увидеть только одну строку, поблювать и идти дальше )))
    ιιlllιlllι унц-унц
  • Trej Gun

    Сообщения: 5305 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 15:59, спустя 20 минут 58 секунд

    artoodetoo, а там больше ничего нет…
    ну можно еще поблевать с

                        if (strpos($key, ':') !== FALSE){
    $keys = explode(':', $key);

    это тоже можно было в регулярку вынести
  • Lirck

    Сообщения: 1658 Репутация: N Группа: Джедаи

    Spritz 23 февраля 2009 г. 16:04, спустя 5 минут 11 секунд


    artoodetoo, а там больше ничего нет…
    ну можно еще поблевать с

                        if (strpos($key, ':') !== FALSE){
    $keys = explode(':', $key);

    это тоже можно было в регулярку вынести

    еслиб было в регулярке - всеб говорили почему не сделал через strpos и explode
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 23 февраля 2009 г. 17:43, спустя 1 час 38 минут 46 секунд

    кто-то из нас двоих тупит неподецки.
    пожалуйста, CTAPbIu_MABP, научи как бы ты изменил это место?

    if (strpos($key, ':') !== FALSE){
    $keys = explode(':', $key);
    ιιlllιlllι унц-унц

Пожалуйста, авторизуйтесь, чтобы написать комментарий!