Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Класс шаблонизатор, интересно мнение опытных ооп-php-программистов

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (1): [1]   

> Без описания
wats
Отправлено: 01 Июля, 2010 - 18:30:06
Post Id


Новичок


Покинул форум
Сообщений всего: 16
Дата рег-ции: Июль 2010  
Откуда: Пермь, Россия


Помог: 0 раз(а)




Здраствуйте! Потребовался простенький класс шаблонизатор с поддержкой вложенных шаблонов, а в ООП я не силен и по разным примерам из сети вроде написал такой класс, все работает, но хотелось бы увидеть мнение и поправки от более опытных людей.
Собственно сам класс:
PHP:
скопировать код в буфер обмена
  1. <?PHP
  2. Class View {
  3.    
  4.     protected $_file;
  5.         protected $_data = array();
  6.    
  7.     public function __construct($file = NULL, array $data = NULL)
  8.     {
  9.         $this->set_template($file);
  10.  
  11.                 if ($data !== NULL)
  12.                 {
  13.                         $this->_data = $data + $this->_data;
  14.                 }
  15.     }
  16.    
  17.     public function factory($file = NULL, array $data = NULL)
  18.         {
  19.                 return new View($file, $data);
  20.         }
  21.    
  22.     public function set_template($file)
  23.     {
  24.         $this->_file = $file;
  25.     }
  26.    
  27.     public function __set($key, $value)
  28.         {
  29.                 $this->set($key, $value);
  30.         }
  31.    
  32.     public function __toString()
  33.         {
  34.                 return (string)View::display();
  35.         }
  36.    
  37.     public function set($key, $value = NULL)
  38.         {
  39.                 if (is_array($key))
  40.                 {
  41.                         foreach ($key as $name => $value)
  42.                         {
  43.                                 $this->_data[$name] = $value;
  44.                         }
  45.                 }
  46.                 else
  47.                 {
  48.                         $this->_data[$key] = $value;
  49.                 }
  50.  
  51.                 return $this;
  52.         }
  53.    
  54.     public function display()
  55.     {
  56.         extract($this->_data);
  57.         require ($this->_file);
  58.     }
  59. }
  60. ?>

Использую так:
PHP:
скопировать код в буфер обмена
  1. require_once ('inc/view.class.php');
  2. // подгружаем основной шаблон
  3. $View = new View('views/template.php');
  4. // вложенный шаблон
  5. $View->content = $View->factory('views/menu.php')
  6.     ->set('name', 'Это вложенный шаблон меню')
  7.     ->set('menu', array(
  8.         'index.php' => 'Главная',
  9.         'news.php' => 'Новости',
  10.         'about.php' => 'Контакты',
  11.     ));
  12. $View->display();

Еще раз напишу, что в ООП PHP я начинающий и поэтому прошу сильно не критиковать по поводу кода представленного выше, а лучше посоветовать как оптимизировать данный класс.

(Отредактировано автором: 01 Июля, 2010 - 19:18:48)



-----
Обычный web-мастер
 
 Top
JustUserR
Отправлено: 02 Июля, 2010 - 02:16:48
Post Id



Активный участник


Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009  


Помог: 17 раз(а)




wats пишет:
А лучше посоветовать как оптимизировать данный класс.
В принципе ваш класс шаблонизатора достаточно стандартный в том числе в плане производительности - однако можно оптимизировать процесс вставки и использования вложенных шаблонов Дело в том что если вы подразумаете использовать систему со списком шаблонов которые могут быть различным образом вложены друг в друга - то можно учесть такой подшаблон который будет включаться во множество других - и например изменение некоторых его параметров отразится во всех использующих его шаблонах В вашем же случае вся иехархия вложенных шаблонов не может использовать одни и те же реальные объекты с общими настройками - поскольку для каждого подшаблона вы обязательно создаете новый экземпляр класса который является собственным значением соответствуюего свойства для родительского шаблона По этой причине имеет смысл добавить возможность подключения определенного шаблона как дочернего объкта по ссылке - причем с сохранением всей его вложенной иерархии если таковая имеется


-----
Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик Улыбка
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
 
 Top
wats
Отправлено: 03 Июля, 2010 - 18:53:11
Post Id


Новичок


Покинул форум
Сообщений всего: 16
Дата рег-ции: Июль 2010  
Откуда: Пермь, Россия


Помог: 0 раз(а)




JustUserR, спасибо, что ответили. Буду переписывать класс.

(Отредактировано автором: 03 Июля, 2010 - 23:47:07)



-----
Обычный web-мастер
 
 Top
koldya
Отправлено: 03 Июля, 2010 - 19:01:07
Post Id



Новичок


Покинул форум
Сообщений всего: 63
Дата рег-ции: Янв. 2010  
Откуда: Украина, Снежное


Помог: 0 раз(а)




Как допишешь выложи на всеобщее обозрение


-----
Помогите в создании CMS!!!
ICQ 473319369
 
 Top
wats
Отправлено: 04 Июля, 2010 - 00:16:43
Post Id


Новичок


Покинул форум
Сообщений всего: 16
Дата рег-ции: Июль 2010  
Откуда: Пермь, Россия


Помог: 0 раз(а)




Вообщем переписал класс, сейчас он стал проще и удобней в работе, прошу оценить.
Сам класс view.class.php
PHP:
скопировать код в буфер обмена
  1. <?PHP
  2. class View {
  3.    
  4.     protected $_template;
  5.     protected $_data = array();
  6.    
  7.     public function __construct($template)
  8.     {
  9.         if (file_exists($template))
  10.         {
  11.             $this->_template = $template;
  12.         }
  13.         else
  14.         {
  15.             exit('File ' . $template . ' not exists.');
  16.         }
  17.     }
  18.    
  19.     public function __set($key, $value)
  20.     {
  21.         $this->_data[$key] = $value;
  22.     }
  23.    
  24.     public function block($block, array $data = NULL)
  25.     {
  26.         if (file_exists($block))
  27.         {
  28.             if ($data !== NULL) extract($data);
  29.             ob_start();
  30.             require $block;
  31.             $out = ob_get_contents();
  32.             ob_end_clean();
  33.             return $out;
  34.         }
  35.         else
  36.         {
  37.             return 'File ' . $block . ' not exists.';
  38.         }
  39.     }
  40.    
  41.     public function display()
  42.     {
  43.         extract($this->_data);
  44.         require ($this->_template);
  45.     }
  46.    
  47. }
  48. ?>

Используем так:
index.php:
PHP:
скопировать код в буфер обмена
  1. <?PHP
  2. header('Content-Type: text/html; charset=utf-8');
  3. // подключаем шаблонизатор и указываем основной шаблон
  4. require_once ('inc/view.class.php');
  5. $view = new View('views/template.php');
  6. // заголовок и приветствие для примера
  7. $view->title = 'Тест шаблонизатора';
  8. $view->hello = 'Добро пожаловать!';
  9. // создаем массив данных для блока меню
  10. $data_menu = array(
  11.     'block_name' => 'Блок меню',
  12.     'links' => array(
  13.         'index.php' => 'Главная',
  14.         'news.php' => 'Новости',
  15.         'about.php' => 'Контакты',
  16.     )
  17. );
  18. // создаем сам блок меню из подшаблона menu.php и массива данных $data_menu
  19. $view->block_menu = $view->block('views/menu.php', $data_menu);
  20. // выводим все на экран
  21. $view->display();
  22. ?>

Основной шаблон template.php:
PHP:
скопировать код в буфер обмена
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  5. <title><?=$title?></title>
  6. </head>
  7. <body>
  8. <h1><?=$hello?></h1>
  9. <?=$block_menu?>
  10. </body>
  11. </html>

И подшаблон menu.php:
PHP:
скопировать код в буфер обмена
  1. <div id="menu">
  2.     <p><?=$block_name?></p>
  3.     <ul>
  4.     <?PHP foreach($links  as $key => $value): ?>
  5.         <li><a href="<?=$key?>"><?=$value?></a></li>
  6.     <?PHP endforeach ?>
  7.     </ul>
  8. </div>

Как вы наверно поняли, подшаблоны подключаются через метод block и можете подключать их таким образом сколько угодно.
Подшаблон обрабатывается вместе с массивом данных предназначенных для него, в примере массивом данных является $data_menu:
PHP:
скопировать код в буфер обмена
  1. $view->block_menu = $view->block('views/menu.php', $data_menu);

Но если вам нужно просто подключить подшаблон без всяких переменных то массив данных указывать не обязательно:
PHP:
скопировать код в буфер обмена
  1. $view->block_menu = $view->block('views/menu.php');

(Отредактировано автором: 04 Июля, 2010 - 00:54:05)



-----
Обычный web-мастер
 
 Top
JustUserR
Отправлено: 04 Июля, 2010 - 02:21:46
Post Id



Активный участник


Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009  


Помог: 17 раз(а)




wats пишет:
JustUserR, спасибо, что ответили. Буду переписывать класс
Пожалуйста! Разработанная вами новая версия класса является действительно более эффективной - а также компоненты вложенных шаблонов являются лучше разделенными и контролируемыми В качестве дополнительных улучшений можно добавить следующие - во-первых перед выполнением оператора extract имеет смысл просмотреть значения всех переменных которые соответствуют ключам хеш-массива - и выполнить их сохранение во временный массив а также после окончания выполнения PHP-кода подшаблона вернуть старые значения переменным - это позволит защититься от потенциальных ошибок при передаче в хеш-массиве $data ключей которые соответствуют реальным переменным Во-вторых можно добавить проверку на синтаксическую правильность подключаемого шаблона - например с помощью функции http://php.su/functions/?runkit-lint-file


-----
Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик Улыбка
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
 
 Top
wats
Отправлено: 04 Июля, 2010 - 12:10:48
Post Id


Новичок


Покинул форум
Сообщений всего: 16
Дата рег-ции: Июль 2010  
Откуда: Пермь, Россия


Помог: 0 раз(а)




JustUserR пишет:
Разработанная вами новая версия класса является действительно более эффективной - а также компоненты вложенных шаблонов являются лучше разделенными и контролируемыми

Спасибо большое Улыбка
JustUserR пишет:
во-первых перед выполнением оператора extract имеет смысл просмотреть значения всех переменных которые соответствуют ключам хеш-массива - и выполнить их сохранение во временный массив а также после окончания выполнения PHP-кода подшаблона вернуть старые значения переменным - это позволит защититься от потенциальных ошибок при передаче в хеш-массиве $data ключей которые соответствуют реальным переменным

Здесь не совсем понял, вы имеете в виду, что возможны конфликты между внешними переменными и переменными полученными из массива $data? Если да, то такого конфликта не может быть, так как метод block работает независимо и возвращает полностью обработанный шаблон где все переменные уже заменены на их значения.
JustUserR пишет:
Во-вторых можно добавить проверку на синтаксическую правильность подключаемого шаблона

Обязательно это учту.


-----
Обычный web-мастер
 
 Top
JustUserR
Отправлено: 05 Июля, 2010 - 01:55:07
Post Id



Активный участник


Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009  


Помог: 17 раз(а)




wats пишет:
Спасибо большое
Пожалуйста! Всегда приятно видеть функциональную библиотеку или класс который работает эффективно и выполняет требуемую работу - и при этом не содержит ненужных функций и излишних наворотов в решении и тем более не использует больших сторонних библиотек Дело в том что несмотря на наличие большого числа фреймворков и библиотек для различных целей - написание собственного решения небольшой задачи гораздо более эффективно чем использование соответствующей функции из фреймворка
wats пишет:
Здесь не совсем понял, вы имеете в виду, что возможны конфликты между внешними переменными и переменными полученными из массива $data? Если да, то такого конфликта не может быть, так как метод block работает независимо и возвращает полностью обработанный шаблон где все переменные уже заменены на их значения.
Действительно я подразумевал такой конфликт имен из-за использования функции extract - однако после проверки вижу что данная функция экспортирует значения хеш-массива в локальную область видимости Тем не менее в общем случае в вашем коде переменная $block может быть подвержена такому перекрытию в случае если в хеш-массиве $data будет передан соответствующий ключ - но это легко решается путем добавления опции EXTR_SKIP к функции extract поскольку по умолчанию подразумевается перезапись опцией EXTR_OVERWRITE
wats пишет:
Обязательно это учту
Можете также посмотреть решение для перехвата фатальных ошибок в PHP если они возникнут к примеру в подключаемом файле - оно описано здесь http://dklab[dot]ru/lib/PHP_CodeFilter/


-----
Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик Улыбка
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
 
 Top
wats
Отправлено: 05 Июля, 2010 - 09:23:05
Post Id


Новичок


Покинул форум
Сообщений всего: 16
Дата рег-ции: Июль 2010  
Откуда: Пермь, Россия


Помог: 0 раз(а)




JustUserR пишет:
Тем не менее в общем случае в вашем коде переменная $block может быть подвержена такому перекрытию в случае если в хеш-массиве $data будет передан соответствующий ключ - но это легко решается путем добавления опции EXTR_SKIP к функции extract поскольку по умолчанию подразумевается перезапись опцией EXTR_OVERWRITE

Вы правы, поправил, заодно изменил $block на $template_block, что бы уж наверняка Улыбка
PHP:
скопировать код в буфер обмена
  1.     public function block($template_block, array $data = NULL)
  2.     {
  3.         if (file_exists($template_block))
  4.         {
  5.             if ($data !== NULL) extract($data, EXTR_SKIP);
  6.             ob_start();
  7.             require $template_block;
  8.             $out = ob_get_contents();
  9.             ob_end_clean();
  10.             return $out;
  11.         }
  12.         else
  13.         {
  14.             return 'File ' . $template_block . ' not exists.';
  15.         }
  16.     }

Едиственное, что пока не использовал runkit_lint_file, так как у меня на локальном сервере выдает ошибку, что такая функция не найдена, наверно должно быть установлено какое то расширение.
С PHP_CodeFilter пока не знаком, обязательно попробую.


-----
Обычный web-мастер
 
 Top
JustUserR
Отправлено: 06 Июля, 2010 - 13:34:05
Post Id



Активный участник


Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009  


Помог: 17 раз(а)




wats пишет:
Вы правы, поправил, заодно изменил $block на $template_block, что бы уж наверняка
Так стало гораздо лучше - причем такие проверки и фильтрации экспортируемых данных нужно не только для того чтобы увеличить безопасность приложения с точки зрения внешнего воздейтсвия на него - но и исключить возможные внутренние сложнообнаружимые ошибки связанные с конфликтами имен и областей видимости
wats пишет:
Едиственное, что пока не использовал runkit_lint_file, так как у меня на локальном сервере выдает ошибку, что такая функция не найдена, наверно должно быть установлено какое то расширение
Для работы с указанной функцией требуется наличие расширения http://php.su/functions/?cat=runkit установочные файлы для которого можно скачать здесь http://pecl.php.net/package/runkit Данное расширение предоставляет набор функций по динамическому управлению исполняемым PHP-кодом - имееются возможности создания и удаления констант и функций а также переопределению их кода во время исполнения и возможности по управлению пространствами имен - в частности это огранизовать собственный интерпретатор PHP-кода например для подключаемых шаболонов причем за счет применения встроенной возможности sandbox-ирования с помощью объекта Runkit_Sandbox это делает процесс еще более эффективным - также имеется возможность эмуляции многопоточных приложений Наличие такой ширикой функциональности данного расширения требует чтобы оно интегрировалось в PHP на этапе его сборки - поэтому вам придется пересобрать PHP из исходных файлов с подключением данного расширения отдельно
wats пишет:
С PHP_CodeFilter пока не знаком, обязательно попробую.
В принципе данная библиотека обеспечивает возможности по префильтрации PHP-кода в подключаемых шаблонов - тем не менее Runkit_Sandbox обеспечивает более широкие возможности по отдельному исполнению подключаемого PHP-кода и делает это более чистым образом


-----
Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик Улыбка
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
 
 Top
wats
Отправлено: 07 Июля, 2010 - 20:25:57
Post Id


Новичок


Покинул форум
Сообщений всего: 16
Дата рег-ции: Июль 2010  
Откуда: Пермь, Россия


Помог: 0 раз(а)




Эх что то я разочаровался, так как не вижу смысла использовать такой класс, так как вместо него можно использовать просто пользовательскую функцию для вставки подшаблонов:
PHP:
скопировать код в буфер обмена
  1.     function block($template_block, array $data = NULL)
  2.     {
  3.         if (file_exists($template_block))
  4.         {
  5.             if ($data !== NULL) extract($data, EXTR_SKIP);
  6.             ob_start();
  7.             require $template_block;
  8.             $out = ob_get_contents();
  9.             ob_end_clean();
  10.             return $out;
  11.         }
  12.         else
  13.         {
  14.             return 'File ' . $template_block . ' not exists.';
  15.         }
  16.     }
  17.  
  18.     $block = block('views/menu.php');

все остальное получается лишнее Огорчение


-----
Обычный web-мастер
 
 Top
JustUserR
Отправлено: 08 Июля, 2010 - 02:06:50
Post Id



Активный участник


Покинул форум
Сообщений всего: 8715
Дата рег-ции: Июнь 2009  


Помог: 17 раз(а)




wats пишет:
Эх что то я разочаровался, так как не вижу смысла использовать такой класс, так как вместо него можно использовать просто пользовательскую функцию для вставки подшаблонов
Использование класса позволяет инкапсулировать ваши данные для шаблона и упростить дальнейшее возможное расширение его возможностей - кроме того можно огранизовать систему в которой подшаблоны будут является наследуемыми классами и использоваться соответствующим образом


-----
Сделать можно все что угодно - нужно только старание, терпение и хороший поисковик Улыбка
Безлимитный web-хостинг от 15 рублей за 40 МБ дискового пространства - http://ihost[dot]oks71[dot]ru/
 
 Top
wats
Отправлено: 19 Июля, 2010 - 09:14:22
Post Id


Новичок


Покинул форум
Сообщений всего: 16
Дата рег-ции: Июль 2010  
Откуда: Пермь, Россия


Помог: 0 раз(а)




JustUserR, вы как всегда правы) Я пересмотрел свое мнение на счет этого.
Сейчас начал создавать свой небольшой mvc-каркас, так сказать мини-фреймворк для будующих приложений по примеру реализации Yii framework, думаю в нем будет использоваться именно этот шаблонизатор.


-----
Обычный web-мастер
 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Программирование на PHP »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB