Yvision.kzYvision.kz
kk
Разное
Разное
399 773 постов41 подписчиков
Всяко-разно
0
04:27, 11 июля 2008

Про Smarty и велосипеды.

Решил написать ответ на пост eudj1n.
Мало кто из кодеров, интересуется "внутренностями" сторонних библиотек, фреймворков и т.д.
Так и я использовал Smarty, и было счастье :) Но природное любопытство взяло своё. Решил посмотреть на Smarty изнутри.
Увидев это огромное количество кода, ничего кроме как "WTF?!" в голову не пришло.
Покапавшись немного в коде, решил что лучше "изобретать велосипеды, чем ездить на тракторах" (c).

Написали с коллегой (Blog post imagep0is0n) маленький шаблонизатор NanoTpl.


<?
final class Tpl
{
 
    private static $vars, $globals;
 
    private static $buffer = '';
 
    public static $tpl;
 
    /**
* Добавление переменной в локальный шаблон
*
* $name - имя переменной
* $value - значение
* $replace - флаг, если установлен в значение отличное от нуля переменная будет перезаписана
*
* @param string $name
* @param string $value
* @param bool $replace
*/

    public static function assign($name, $value, $replace = false)
    {
        if (isset(self::$vars[$name]) and ! $replace)
        {
            if(is_array(self::$vars[$name]) && is_array($value))
                self::$vars[$name]=array_merge(self::$vars[$name],$value);
            elseif(is_array(self::$vars[$name]))
                self::$vars[$name][]=$value;
            else
                self::$vars[$name] .= $value;
        }
        else
            self::$vars[$name] = $value;
    }
    /**
* Добавление глобальной переменной (будет доступна во всех шаблонах)
*
* $name - имя переменной
* $value - значение
* $replace - флаг, если установлен в значение отличное от нуля переменная будет перезаписана
*
* @param string $name
* @param string $value
* @param bool $replace
*/

    public static function assignGlobal($name, $value, $replace = false)
    {
        if (isset(self::$globals[$name]) and ! $replace)
        {
            if(is_array(self::$vars[$name]) && is_array($value))
                self::$vars[$name]=array_merge(self::$vars[$name],$value);
            elseif(is_array(self::$vars[$name]))
                self::$vars[$name][]=$value;
            else
                self::$globals[$name] .= $value;
        }
        else
            self::$globals[$name] = $value;
    }
    /**
* Обработка шаблона , результат будет записан в переменную $content (используется при отображении главного шаблона)
*
* $tpl - имя шаблона
* $global - использовать глобальные переменные
*/

    public static function compile($tpl = null, $global = false)
    {
        $tmp = self::fetch($tpl, $global);
        if ($tmp)
        {
            self::$buffer .= $tmp;
        }
    }
    /**
* Обработка шаблона , возвращает html
*
* $tpl - имя шаблона
* $global - использовать глобальные переменные
*/

    public static function fetch($tpl = null, $global = false)
    {
        $out = '';
        if (null !== $tpl)
            self::$tpl = $tpl;
        if (is_readable(TPL_DIR . DIRECTORY_SEPARATOR . self::$tpl) and is_file(TPL_DIR . DIRECTORY_SEPARATOR . self::$tpl))
        {
            if (! is_array(self::$vars))
                self::$vars = array();
            if ($global)
            {
                if (is_array(self::$globals) and ! empty(self::$globals))
                    self::$vars += self::$globals;    
            }
            if (! empty(self::$vars))
            {
                foreach (self::$vars as $k => &$v)
                {
                    $$k = $v;
                }
                self::$vars = array();
            }
            $level = error_reporting();
            error_reporting(E_ALL);
            ob_start();
            include(TPL_DIR . DIRECTORY_SEPARATOR . self::$tpl);
            $out = ob_get_contents();
            ob_end_clean();
            error_reporting($level);
            self::$tpl = null;
        }
        else
        {
            trigger_error('template "' . self::$tpl . '" not found', E_USER_WARNING);
        }
        return $out;
    }
    /**
* Отображает шаблон
*
* $tpl - имя шаблона
*/

    public static function display($tpl="main.tpl")
    {
        self::assign('content', self::$buffer);
        self::$buffer = self::fetch($tpl, true);
        self::$globals = array();
        print self::$buffer;
    }
 
}
?>

Мал по размерам, быстро работает.Всегда готов к работе)) Приведу здесь небольшое сравнение Smarty и NanoTpl.
Smarty
<?php
require('class/Smarty.class.php'); //подключаем класс
$smarty = new Smarty(); //создаем экземпляр
$smarty->template_dir = '/web/www.domain.com/smarty/templates'; //директория с шаблонами
$smarty->compile_dir = '/web/www.domain.com/smarty/templates_c'; //тут "скомпилированные" шаблоны
$smarty->cache_dir = '/web/www.domain.com/smarty/cache'; //кеш
$smarty->config_dir = '/web/www.domain.com/smarty/configs'; //еще дирректория :)
$tags = array('php','Smarty','шаблонизатор'); //создаём массив
$smarty->assign('name','eudj1n'); //передаём в шаблон данные
$smarty->assign('tags',$tags);
$smarty->display('main.tpl'); //отображаем главный шаблон
?>

Сам шаблон


Smarty


//передадим привет eudj1n-у. :)
Hello, {$name}!
//отобразим значения массива
{foreach from=$tags item=tag}
{$tag}
{/foreach}


NanoTpl
<?php
require('class/Tpl.class.php'); //подключаем класс
define('TPL_DIR', ROOT_DIR . DIRECTORY_SEPARATOR . 'tpl'); //определяем константу - дирректория где лежат наши шаблоны
$tags = array('php','Smarty','шаблонизатор'); //передаём в шаблон данные
Tpl::assign('name','eudj1n');
Tpl::assign('tags',$tags);
Tpl::display(); //показываем всем главный шаблон по-умолчанию подгружается "main.tpl"
?>
Сам шаблон


Smarty


//передадим привет eudj1n-у. :)
Hello, <?=$name?>!
//отобразим значения массива
foreach ($tags as $tag){?>
<?=$tag?>
<?}?>

Как видите NanoTpl прекрасно справляется со своей работой. И работа с ним ничють не сложнее чем со Smarty.
Многие наверно сейчас скажут, что использовать php в шаблонах - зло. Т.к. можно писать туда всё что хочешь (запросы к бд и т.д.)
Кстати и разработчики Smarty используют это, как плюсик в безопасности шаблонизатора:
"Security: Templates do not contain PHP code.Therefore, a template designer is not unleashed with the full power of PHP, but only the subset of functionality made available to them from the programmer (application code.)"
Но стоит ли жертвовать производительностью в пользу такой сомнительной "безопасности"?
Вы можете существенно доработать NanoTpl под свои нужды, т.к. он только и умеет что передавать данные в шаблон.
Хочу еще раз сказать: небойтесь изобретать велосипеды. Делая это вы несомненно приобретёте опыт и возможно ваш велосипед будет лучше чем соседский :)
0