Здравствуйте! Возникла у меня идея оградить сервер от многочисленных загрузок файла шаблона при выводе новостей. Допустим мы выводим 20 новостей, допустим, из них для 15 задан шаблон active1.tpl, для 3-х active2.tpl и для 2-х active5.tpl. Т.е. не имеет смысла обращаться к серверу за файлом active1.tpl 15 раз (а если высокая посещаемость?). Сильным серверам все равно (даже если по 50 новостей выводить), но если сервер и так перегружен (во время атак). Я набросал пример. Там даны комментарии. Подскажите, пожалуйста, как мне лучше реализовать идею? Файл вывода новостей. Код (Text): ###################################### $tmp = "active1.tpl"; // шаблон установленный по умолчанию $dd = array(); $cache = array(); // data - исходный массив данных // шаблон, определенный для текста $dd['a']['tpl']="active1.tpl"; $dd['b']['tpl']="active1.tpl"; $dd['c']['tpl']="active3.tpl"; $dd['d']['tpl']="active1.tpl"; $dd['e']['tpl']="active5.tpl"; $dd['f']['tpl']="active1.tpl"; // текст, который должен отображаться в заданном шаблоне $dd['a']['txt']="первый шаблон!.tpl"; $dd['b']['txt']="второй шаблон!.tpl"; $dd['c']['txt']="третий шаблон!.tpl"; $dd['d']['txt']="четвертый шаблон!.tpl"; $dd['e']['txt']="пятый шаблон!.tpl"; $dd['f']['txt']="шестой шаблон!.tpl"; // функция вывода шаблона и текста // $in - входящее имя шаблона (файла) function tpl_out($in="default"){ global $tpl; // содержит в себе данные текущей итерации static $out; // статическая переменная держит в себе массив уникальных шаблонов, где ключ - имя шаблона ######### // если массив содержит данные с ключём входящего имени шаблона, то выводим "кешированный" шаблон if (!empty($out[$in])) { $ff = $out[$in]; // тут проблема. Переменная в шаблоне не заменяется данными объявленными в глобальной переменной $tpl return $ff; // иначе подгружаем файл с указанным именем шаблона } else { ob_start(); include templates_directory.'/'.$in; $out[$in] = ob_get_contents(); // добавляем шаблон в массив уникальных шаблонов ob_end_clean(); return $out[$in]; } ######### } //print - перебор данных исходного массива foreach ($dd as $ddk => $ddv) { $tpl = array(); $tpl['post'] = $ddv['txt']; // определяем текст для переменной в шаблоне. echo tpl_out($ddv['tpl']); // задача функции - использовать (подгружать) файл шаблона только один раз после первого упоминания в итерациях } echo "<hr />"; // элемент декора :) ###################################### Файл active1.tpl. (шаблоны с другими номерами идентичны) Код (Text): <hr /> <div style="border: 1px solid #ccc; background-color: #D2F0DA;">Шаблон №1: <br /> $tpl['post'] <br /> ".$tpl['post']." <br /> <?php echo $tpl['post']; ?> </div> <hr />
если новость и шаблон не меняются месяцами или годами, имеет смысл результат применения шаблона запихать в файл или бд.
а если меняется? Смысл в вашем предложении есть, но нет универсальности ))) Я же не знаю как пользователь будет распоряжаться файлами... ЗЫ Это для бесплатной cms.
Как вы предлагаете выполнить кеширование? В файл? - меняем шило на мыло. %) у нас и так шаблоны - это файлы. В базу? - куча ненужных запросов. о_О В переменную (массив) - я работаю в этом направлении. Но не выходит. Пробовал создавать функции с содержимым шаблона через create_function, но он мне что-то не дался. (( Может кто-то видел где-то что-то подобное? Наверняка есть решение. Помогите пожалуйста с приведенным примером )
создавать объект шаблона (заполняя его данными из файла) при обработки новости. при обработки следующей новости проверять, нужен ей шаблон из существующих объектов или подгружать новый. после отработки собственно, уничтожать все объекты.
Вы мне классы предлагаете? При загрузке шаблона (как у меня в примере) - переменные заменяются раньше, чем шаблон успевает попасть в какой либо контейнер.... Вот в чем проблема. Или я вас не понял. Можно примерчик для доступности?
можно как класс, можно, да как угодно можно это реализовать. механика какая у вас? tpl что хранит в себе ?! html с метками аля - Код (Text): {main_menu} или подключением компанентов аля - Код (Text): <?=$core->render->main_menu?;> ?! в принципе и там и там алгоритм я бы делал один и тот же, примерно следующий: Код (Text): // берём новость, смотрим какой тип шаблона ей нужен. if (!in_array('id_шаблона',$tpl_list)) { // нужного ей шаблона нет в массиве шаблонов (уже загруженных с файла) // загружаем в $tpl_list[] новый шаблон, после чего // обрабатываем вывод новости } else { // шаблон уже загружен, значит грузить вновь его не нужно // просто обрабатываем вывод новости } // освобождаем массив с загруженными шаблонами. что-то в этом духе. с компанентами (классами, виджетами) как вам удобнее будет, алгоритм собственно такой же.
@Mr.Miksar, [ повторное ] чтение из файла это довольно шустрая операция, кешируемая на уровне ОС. это не то, что стоит оптимизировать в скрипте! замерь затраты времени на основные операции и работай над главным
Всю механику привел в примере. только вместо запроса из БД сделал готовый массив. Шаблон содержит переменные. Обычные самые. В исходной версии движка они выводились в шаблоне, например, как <?=$tpl['id']; ?>. Для совместимости старых версий движков - хотелось бы структуру шаблона сохранить. И вашу идею и пытался реализовать (это была моя первая версия с массивом, но с функцией (через static) показалось как то удобнее, хотя и не критично). В общем, не получается с моей структурой. ))) Еще идеи будут? Это мне уже предложили. Буду тестировать ) Дык вот и стараюсь везде учесть возможные "неровности" )) Спасибо! )
Итак в своем примере сделал следующие поправки: Код (Text): foreach ($dd as $ddk => $ddv) { $tpl = array(); $tpl['post'] = $ddv['txt']; $st = array_sum(explode(" ", microtime())); echo tpl_out($ddv['tpl']); // задача функции - использовать (подгружать) файл шаблона только один раз после первого упоминания в итерациях $tot = round(((array_sum(explode(" ", microtime()))) - $st), 6); echo "<b>".$tot."</b>"; } Время с округлением до 6 знаков после запятой. подключался один и тот же файл. Каждый столбец - обновление браузера. Каждая строка - последующее подключение файла. Вот мои результаты: // если с кешированием в массив (в функции через статик) 0,000823 0,000773 0,000817 1,6E-5 1,5E-5 1,6E-5 1,2E-5 1,3E-5 1,3E-5 1,1E-5 1,1E-5 1,2E-5 // если без кеширование - прямое подключение 0,0007 0,000758 0,000708 0,000228 0,000237 0,000218 0,00017 0,000181 0,000166 0,000169 0,000166 0,000168 Итак - результат из массива выводится практически на 0.0002 быстрее чем подключение файла. В любом случае подтвердилось и то, что повторное подключение файла не происходит, а берется он из некоего кеша ОС.
Я прикидывал вывод (вроде как) 1000 или 10000 новостей. тогда время вывода сокращается с 32с. до 3с. Но это так... эксперимент )) Провел опыт и дал пищу для ума - а уж как кто воспользуется - дело его. Да, не забывайте еще время на запросы в БД. Время загрузки других файлов с сервера. Время есть куда поберечь ЗЫ Функцию кеширования через статик все же написал. Но есть минусы. Кому интересно - кину в личку.
Код (PHP): // сохраняем шаблон, сериализуем $ser = serialize(file_get_contents("template.tpl")); // ----- $tpl['post'] = "Hello"; eval(" ?> ".unserialize($ser)." <?php "); ...... $tpl['post'] = "Bye"; eval(" ?> ".unserialize($ser)." <?php "); не проще? ... хотя кому как.