php_templates: Не предсказуемое поведение tmpl_set_global

Altex

Новичок
php_templates: Непредсказуемое поведение tmpl_set_global (+немного о blitz segfault)

PHP 5.2.10
php_templates 1.7.2-5.2.0
windows vista 32

Есть один и тот же шаблон
Код:
Sitename is: {SITENAME}
--------------------------
product    | price
--------------------------
<tmpl:row>
{SITENAME}:{product}    {price}
</tmpl:row>
И вот такой код

PHP:
<?php

$template = tmpl_open('test.tpl');

$products = array(
    array(
        'product' => 'first',
        'price' => '10p',
    ),
    array(
        'product' => 'second',
        'price' => '20p',
    ),
    array(
        'product' => 'third',
        'price' => '30p',
    ),
);

tmpl_set_global($template, 'SITENAME', 'testsite');

while($data = each($products)) {
  tmpl_iterate($template, 'row');
  tmpl_set($template, 'row', $data);
}

echo tmpl_parse($template);
Результат работы
Код:
Sitename is: testsite
--------------------------
product    | price
--------------------------

:first    10p

:second    20p

:third    30p
Какое-то не логичное поведение глобальной переменной шаблона. Хорошо, я допускаю, что set_global проходит по всем контекстам только еслиони созданы, пробую по-другому:

PHP:
<?php

$template = tmpl_open('test.tpl');

$products = array(
    array(
        'product' => 'first',
        'price' => '10p',
    ),
    array(
        'product' => 'second',
        'price' => '20p',
    ),
    array(
        'product' => 'third',
        'price' => '30p',
    ),
);

while($data = each($products)) {
  tmpl_iterate($template, 'row');
  tmpl_set($template, 'row', $data);
}

tmpl_set_global($template, 'SITENAME', 'testsite');

echo tmpl_parse($template);
Результат работы
Код:
Sitename is: testsite
--------------------------
product    | price
--------------------------

:first    10p

:second    20p

testsite:third    30p
Как-то тоже не сильно логично.

И самая раскошная интерпритация глобальных переменных шаблона

PHP:
<?php
$template = tmpl_open('test.tpl');

tmpl_set_global($template, 'SITENAME', 'testsite');
tmpl_set_global($template, 'SITENAME', 'testsite');
Результат работы
Код:
PHP Fatal error:  Undefined tag/context "/row" in <...>test.php on line 6

Объясните, пожалуйста, как правильно работать с глобальными переменными шаблонов в php_templates?

-~{}~ 26.07.09 12:46:

Я знаю автор php_templates иногда появляется на форуме, поэтому я надеюсь он тоже сможет что-нибудь прояснить.
 

fixxxer

К.О.
Партнер клуба
1) это известный баг
2) на php_templates давно забито всеми, а вообще можно сделать свой класс и протаскивать глобалсы во все итерации руками
3) use blitz
 

Altex

Новичок
Автор оригинала: fixxxer
а вообще можно сделать свой класс и протаскивать глобалсы во все итерации руками
Вот именно этого и не хочется. Потомучто тогда стираются различия между tmpl_set и tmpl_set_global :)

Автор оригинала: fixxxer
3) use blitz
Файл test.tpl
Код:
second
PHP:
<?php

$TplEngine = new Blitz();

$TplEngine->load("first\n{{include('test.tpl')}}");
echo $TplEngine->parse();
echo $TplEngine->include('test.tpl');
// Если раскомментировать следующую строчку или закоментировать предыдущую - баг проявляться НЕ будет
//echo $TplEngine->include('test.tpl');

unset($TplEngine);

echo "this will be never shown\n";
результат выполнения
Код:
first
second
second
Ошибка сегментирования (core dumped)
результат отладки
Код:
Program terminated with signal 11, Segmentation fault.
#0  zend_hash_destroy (ht=0xb7719ed8) at /home/altex/altex/php-5.2.10/Zend/zend_hash.c:524
524                     p = p->pListNext;

 zend_mm_heap corrupted
ошибка возникает при освобождении памяти
в blitz.c
в static void blitz_free_tpl(blitz_tpl *tpl) /* {{{ */

Код:
    if (tpl->iterations && !(tpl->flags & BLITZ_FLAG_ITERATION_IS_OTHER)) {
        zval_dtor(tpl->iterations); // Вот тут происходит ошибка
        efree(tpl->iterations);
        tpl->iterations = NULL;
    }
тоесть там где освобождается php массив с итерациями в шаблоне

судя по ченчлогу этот баг исправили 4 месяца назад, но видимо не до конца исправили

0.6.8 version 13 march 2009
- Segfault in nested includes with user-defined functions was fixed (in some cases there could
be a double free of method result at shutdown stage). See bug #245 for detais.

Зарегистрироваться на сайте с багрепортами не получилось, ошибка отправки сообщения с паролем. Поэтому посмотреть что там был за баг не получилось. Как вобщем и запостить новый баг. Написал в рассылку в пятницу, пока ни одного ответа.

blitz 0.6.8
win/lin
php 5.2.6,5.2.10

-~{}~ 26.07.09 13:42:

Основная проблема блица в том, что нельзя указать базовый путь к шаблонам. В результате даже в инклудах в шаблоных придётся писать полный путь либо делать chdir, и то и то плохой вариант. Компромисный вариант - сделать свою функцию inc в которой делать include но подставлять базовый путь. Жать что при этом всё тот же segfault получается.

Буду рад советам попробовать ещё какие-нибудь шаблонные движки. Проект высоконагруженный, нужен быстрый движок.
 

fixxxer

К.О.
Партнер клуба
эээ
echo $TplEngine->include('test.tpl');

это ты что-то странное делаешь:)) хотя падать не должно конечно

в blitz можно указать путь к шаблонам в ini

если надо менять в рантайме, могу поделиться своими патчами, они это умеют и еще всякое

а юзать свой incl() это логично, сам так делаю ;)

а на багтрекер хрен зайдешь, ага, там sendmail валяется. надо фишера пнуть бы
 

Altex

Новичок
Автор оригинала: fixxxer
echo $TplEngine->include('test.tpl');

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

в blitz можно указать путь к шаблонам в ini
Ого, не знал, спасибо. А где можно про это почитать? Или пример использования?

если надо менять в рантайме, могу поделиться своими патчами, они это умеют и еще всякое
Поделись пожалуйста.

а юзать свой incl() это логично, сам так делаю ;)
я тоже так делаю, и был бы счастлив, если бы при этом не сегфолтилось. Могу выложить пример именно с этой реализацией, просто не стал этого делать, чтобы не заграмождать код, но суть в том, что происходит всё тот же самый сегфолт в том же самом месте. Ещё там поведение функции include сильно отличается от описанного в документации, но слава Богу оно хотя бы логичное и соответсвует здравому смыслу (я имею ввиду, что передвавать в эту функцию нужно локальные а не глобальные переменные, а если они не переданы, то беруться из текущего контекста. А глобальные в любом случае передаются, на то они и глобальные.), однако напрягает, что локальные беруться автоматически только при вызове из шаблона функции include, а не из php файла. Из-за этого приходится делать вот такие извращения типа $this->include($tplName, $this->getIterations()) для того, чтобы поведение функции include было однозначным и при вызове из php файла, и при вызове из шаблона.
 

fixxxer

К.О.
Партнер клуба
вобщем

http://symbi.org/misc/blitz-patches.diff

-/* {{{ proto new Blitz([string filename]) */
+/* {{{ proto new Blitz([string filename [, string templates_path]]) */

задает в конструкторе путь к шаблонам в рамках данного инстанса Blitz, по умолчанию совместимое поведение - берет путь из ini

+/* {{{ proto void Blitz->set_send_context_to_callbacks(bool send_context_to_callbacks) */

включает передачу в коллбэки первым параметром текущего контекста. патч там дико смешной :)

удобно для написания хелперов

+/* {{{ proto void Blitz->set_autoescape(bool autoescape) */
включает автоескейпинг при выводе всех переменных, кроме тех, которые с префиксом STD_PHP_INI_ENTRY("blitz.no_autoescape_prefix")


ах да,
-#ifdef COMPILE_DL_BLITZ
-ZEND_GET_MODULE(blitz)
-#endif
это тупо убирал чтобы собиралось статиком, не было времени разобраться как сделать правильно - верни если сошку надо

дифф с версии 0.6.7, но по идее на .8 тоже должно накладываться

а глюкота с инклюдами меня в свое время настолько достала, что я протолкнул патч для ini_set blitz.disable_includes =) собственно там это родовая травма - первые версии умели только инклюд и коллбеки но не умели контексты, и код в итоег слабо интегрирован
 

fisher

накатила суть
tmpl_set_globals кажется надо звать перед парсингом - тогда он вроде бы сам заходит во все контексты и сетит.
насчет blitz и невозможности зарегиться - был косяк с мейлером, да, я его вроде поправил - добавьте, пожалуйста, в багтракер. сегфолт который я фиксил - это скорее всего совсем другой сегфолт!

что куда кто писал - ничего не получал (или не помню).
фиксер - что там у тебя за патчи ченить новое е?

Ещё там поведение функции include сильно отличается от описанного в документации, но слава Богу оно хотя бы логичное и соответсвует здравому смыслу (я имею ввиду, что передвавать в эту функцию нужно локальные а не глобальные переменные, а если они не переданы, то беруться из текущего контекста. А глобальные в любом случае передаются, на то они и глобальные.), однако напрягает, что локальные беруться автоматически только при вызове из шаблона функции include, а не из php файла. Из-за этого приходится делать вот такие извращения типа $this->include($tplName, $this->getIterations()) для того, чтобы поведение функции include было однозначным и при вызове из php файла, и при вызове из шаблона
эй чуваки а написать мне что напрягает? выуживай потом мнения в ваших интернетах!
насчет инклюда из пхп-файла - а кстати непонятно че ваще напрягает. непонятно почему всю итерацию надо вдруг сетить в другой шаблон если оно сетится из пхп-файла.
 

fixxxer

К.О.
Партнер клуба
>> фиксер - что там у тебя за патчи ченить новое е?

да вощемта все то же что обсуждали, получение контекста в коллбэках и автоескейпинг. а, еще возможность указать blitz.path для конкретного инстанса. у меня там сделано грубовато на скорую руку потому и не высылал.
 

Altex

Новичок
Автор оригинала: fisher
tmpl_set_globals кажется надо звать перед парсингом - тогда он вроде бы сам заходит во все контексты и сетит.
К сожалению нет, я пробовал :( Там вообще очень печальные ошибки.
Автор оригинала: fisher
насчет blitz и невозможности зарегиться - был косяк с мейлером, да, я его вроде поправил - добавьте, пожалуйста, в багтракер. сегфолт который я фиксил - это скорее всего совсем другой сегфолт!
Добавил
Автор оригинала: fisher

что куда кто писал - ничего не получал (или не помню).
Я писал в список рассылки по адресу, который в мануале указан там же где и ссылка на багтрекер.
Автор оригинала: fisher
эй чуваки а написать мне что напрягает? выуживай потом мнения в ваших интернетах!
Дык не понятно куда писать ) Скажи куда, буду писать. Пока пишу сюда
Автор оригинала: fisher
насчет инклюда из пхп-файла - а кстати непонятно че ваще напрягает.
непонятно почему всю итерацию надо вдруг сетить в другой шаблон если оно сетится из пхп-файла.
Не совсем понял вопроса. Для меня проблема видится в том, что поведение функции include различается при вызове из шаблона и при вызове из php файла. При вызове из шаблона она автоматически сетит всю итерацию. При вызове из php файла она ничего не сетит вообще. Приходиться сетить вручную.
 

fisher

накатила суть
Автор оригинала: Altex
Добавил
вижу, спасибо. дубль по-русски удалил. не надо туда писать по-русски.

Автор оригинала: Altex
Дык не понятно куда писать ) Скажи куда, буду писать. Пока пишу сюда
alexey D0T rybak AT gmail D0T com - туда можно по-русски
blitz-php AT googlegroups D0T com - туда только по-английски

Автор оригинала: Altex
Не совсем понял вопроса. Для меня проблема видится в том, что поведение функции include различается при вызове из шаблона и при вызове из php файла. При
вызове из шаблона она автоматически сетит всю итерацию. При вызове из php файла она ничего не сетит вообще. Приходиться сетить вручную.
а, понял. лан, придумаем что-нибудь. щас вообще будет глобальный рефакторинг, слишко много мусора и накопившихся фич, которые стало просто тяжело добавлять.
 
Сверху