Pull to refresh

Comments 155

Могу добавить, что на простой mysql (в смысле без каких-либо оптимизаций), eval с базой выполняется ЕМНИП в два раза дольше, чем eval с файлами.
Ну с БД отдельный разговор. Просто так пихать в базу представления, конечно, смысла нет. Но если сильно надо, то только eval и сможет помочь. :)
Вывод комментариев через рекурсию не лучший вариант в мире
Действительно, ищите просчеты в архитектуре. Никаких рекурсий! , если вы хотите быстрой и СТАБИЛЬНОЙ работы.
Потом будете долго ломать голову, надо какой-нибудь "ошибкой"... а ошибка может быть очень малозаметная, например утечка памяти.
Однозначно переделывайте архитектуру пока не поздно...
Архитектуру продумана, переделывать не придётся. Достаточно переписать представление. От рекурсии избавиться не смогу — у меня ведь дерево, а не линейный набор. Скорее всего поступлю так, как посоветовал следующий комментатор.
И что, что дерево?
Я на RoR реализовал одним циклом по планарному хэшу. Там, правда, участвовал level, а хэш был отсортирован правильно (не помню сейчас, как я это сделал).
Но в результате все получалось правильно вставленными дивами, которые можно было хайдить, чтобы свернуть цепочку подответов.
Извините за невежество, но что такое планарный хеш (или массив)? И как это касается PHP?
С точки зрения PHP - это обычный массив.
В Руби они делятся: массив это то, что с индексами "1, 2, 3...", причем если был инициализирован 1й и 5й, то появятся 2, 3, 4 равные nil, хэш - это то, что в PHP называют "массивы" - какие попало индексы.

Планарный в плане "1 -> первый камент", "2 -> второй камент", даже если второй - это ответ на первый.
А не в первом содержится "comments -> array(...)".
Рекурсия в деревьях - ошибка архитектуры, да и вообще рекурсией никто из специалистов не советует пользоваться... я честно говоря не встречал не в одном серьезном проекте рекурсии... Дерево можно спокойно выбирать и как вы говорите "линейно". NS и кучу других алгоритмов никто не отменял.... вперед дерзайте.
Уже дерзаю. Благодарю за ссылку на алгоритмы, которую вы привели ниже.
Хм, вообще не пользоваться рекурсией тоже не есть хорошо. Как, например, сделать левый обход дерева, или проверить граф на цикл, при попытке пере-аттачить комментарий к своему же потомку? Это стандартные алгоритмы, для их реализации необходим стек, зачем изобретать велосипед, если разработчики ЯП уже реализовали его, предоставив рекурсивные вызовы.

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

Нетрудно догадаться что движок шаблонов (I'm Smarty user), пробегая по этой структуре, в первом случае должен поставить <DIV>, а во втором определенное кол-во </DIV>

При том, в силу линейности структуры, присобачить в середину еще кусок дерева не представляет никакой сложности (если я вдруг захочу сделать динамическую подгрузку веток комментов)
Знаете, алгоритмов много :) Кто как хочет так и ... Просто, персчет массива после его получения (путем запроса к БД)- трата ресурсов имхо.
Плохому программисту рекурсия мешает...
Рекурсия - потеря контроля (как данных так и возможно сущностей) имхо. Каждая потеря контроля - потенциальный глюк. Если можно обойтись без рекурсии - значит надо обходится без неё. Если нет - искать алгоритм. Ну уж если припекло - можно пользоваться. Никто не запрещает :) Просто вы должны быть уверены что в этом участке вы не потеряете контроль.
да. особенно вызывать include в цикле. О ужас!!!!

Я предлагаю делать древовидный вывод комментариев таким образом (как и сам использовал):
Получаю в контроллере массив комментариев (большой или маленький - вам решать)
В соответсвенном вьюве НИ В КОЕМ случае не инклюдить снова этот вьюв. Лучше написать в теле view рекурсивную функцию, которая обходит Ваше дерево с комментариями и оотображает нод за нодом. Таким образом файл инклюдится движклм один раз.

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

Цикл был по хэшу, в зависимости от разности level предыдущего и текущего выводились начала-концы блоков. И сам камент.

Алгоритм был немного завернутый, но красивый и правильный.
В конце концов, для этого мы и программисты, чтобы алгоритмы писать.

А то модно стало тесты на скорость вместо этого писать :)
Зря вы так по поводу тестов производительности.

На сколько я понял, в вашем случае, основной идеей была правильная сортировка и выставление уровней. Согласен,тогда можно обойтись и линейным массивом. Только я не понял, чем вызов 100 вьюшек каммента, и 200 вызовов вьюшек начала и конца блока лучше 100 рекурсивных вызовов каммента? Это ведь в 3 раза больше представлений. И не вижу причин не использовать рекурсии. У вас в сортировке тоже ведь рекурсия использовалась?
Я точно не помню, но мне кажется, что не было. Вот как сделал - сейчас затруднюсь сказать, подумал - не помню. Но при использовании рекурсии получается дерево, планарный массив получается криво.
На вызовы я не заморачивался, RoR хорошо все кэширует.

В моем случае идеей было - вывод комментариев из БД в древовидном представлении с возможностью "скрыть-показать" поддерево. У вас какая-то другая задача?

Минусы рекурсии сами назовете? :)
Задача та же, подход другой. О минусах рекурсии помню, но чтоб оценить лучше это, чем в 3 раза большее количество вызовов представлений но линейно, или нет, нужно проводить тесты. Да, те самые тесты, которые теперь "стало модно писать". ;)

За вариант реализации дерева спасибо. Обязательно попробую.
Вспомнил детали.
На RoR я пользовался плагином, организующим дерево в БД. Там right и left прописывались для каждой записи (обновлялись при вставке, удалении, переносе нода в другое место). В результате, если выбирать записи в порядке возрастания right и по дате создания (можно по id), то они выдавались точно в том порядке, в котором должны были бы отразиться на экране. Дополнительно я высчитывал только level, но это не сложно, имея для каждой записи parent_id.

По вызовам представдений. Два из них были примитивными - открытие дива, еще что-то. Максимум - вставка id для дива, чтобы было как хайдить. Второй - одни закрытия дивов. Так что можно кэшировать хоть чем :)
Я понял. Это и есть алгоритм Nested Sets, о котором писал Maxic.
И плюс в карму за полезную дискуссию. :)
Больше к Apostol:
да и у вас не все понятно, можно поподробнее... где и как и на каком этапе ... тогда можно будет разобрать и ваше решение :)

Есть :) Получать массив ровно такой какой должен быть (block paging желательно с возможность сортировки по карме, дате и т.п. не кто не отменял? а простыню в 200 комментов что читать, что загружать нудно, поверьте разработчики хабры... половину комментов просто игнорируется и читается выборочно, обычно обращается внимание на карму коммента, или все читают до единого коммента?)... далее, я вообще не понимаю зачем что-то обходить и инклудить потом? Ну есть же row['level']... стройте себе дерево... что там инклудить? Модули? Каждый модуль - один раз, потому как ВСЕ данные мы уже получили, и нам надо "расширенные" поля имеющихся УЖЕ данных, которые мы получим обработкой модулей. Не понятно что там инклудить... может темплейт самого коммента? :) ну так тоже... один раз инклуд в память его, и юзайте сколько влезет потом...
Ладно, хорошо, предположу что инклудятся комменты, которые хранятся в дереве файловой системы... но
это простое расточительство ресурсов!... хранить в файловой системе можно и нужно, но только большие страницы... комменты в основном маленькие.... как выход... страницы хранить в файловой системе, а комменты в поле description (потому как у комментов обычно нет description) ноды/страницы/представления или как вы там его еще обозвали в вашей БД.
Хм... Вы верно заметили про комменты на хабре. Я тоже если "сильнамногакаментов", что читаю только которые либо с зеленым рейтингом, либо с рейтингом <-5 (интересно знать, что же такое сказал хабрапользователь, что его беспощадно заминусовали... )
Но если ветвь дискусси оказывается достаточно интересной, то читаю по возможности все.

Я сейчас разрабатываю в своем проекте такой подход - во первых, выводить комментарии под постом таким образом, чтобы выводилось дерево вглубь максимум 3-4 уровня вложения. Дальше кликаем ссылку - "раскрыть дерево"/"раскрыть ветвь", после чего нашим любимым XMLHTTPRequest'ом грузится остальная часть дискуссии.
Во вторых должна быть опция "скрыть ветвь" (достаточно обычного JS + возможность запоминать состояние при повторном просмотре - Cookie)
Сейчас тестирую и принимаю все предложения "за" и "против"...
Любить не запретишь...:) Любовь зла - полюбишь и ... сами знаете, тем более XMLHTTPRequest... я его тоже любил...но потом извините, это оказался тупиковый путь развития. Забейте на все кодировки и переходите на UTF-8 - будете спать спокойно. И выбирите себе любой fw: будь то jquery, mootoolth, прототайп... чисто человеческий совет. XMLHTTPRequest путь в никуда (сейчас от любителей получу куча минусов - причем 100% не аргументированных а чисто фанатских, но знаю на что иду.. хочу уберечь драгоценное время людей)... я на форуме писал про ошибки ... что-то правилось... но концепция - нет... а это самое главное. Только за один backend и вызов "шапки" (я понимаю для поддержки кодировок...но... UTF-8 жив и живее всех живых) XMLHTTPRequest - не стоит времени на него потраченного...

P.S. Возьмите например jquery - там есть куча хороших библиотек для дерева... например одного моего знакомого http://news.kg/wp-content/uploads/tree/d…
По этому принципу можно и комменты "рулить"
Э-э-э.... Я вообще-то образно написал о XMLHTTPRequest'e
Я сам юзаю Prototype. Зачем изобретать велосипед? ;-)
Честно говоря ветка комментов далее 4-5 уровня и не уходит :) во всяком случае я редко встречал...
Поэтому в комментах можно выводить сразу все уровни, но... не все комменты.
Сортировку комментов (хватит по карме и дате, а также кол-ву уровней) и paging я советовал бы разработчикам Хабры прикрутить в superhabr
по поводу paging - хорошо с линейными комментариями. Но для древовидных - мне кажется, неудобно.
Честно говоря не увидел аргументов, почему? Нормально вполне. Далее 4-5 уровня все равно не заходят.
А если много то уже никто связи с топиком родителя и так не видет :)
ну вот хотя бы данная дискуссия - тянется от http://habrahabr.ru/blog/php/40532.html#…
Где вы предлагаете ее разорвать для пейджинга?
Если и разрывать, то только между самыми верхними нодами - как отдельные деревья. Вот тогда вопрос - зачем в этом случае paging? Ведь лучше свертывание/развертывание ?
Или мы о разных вещах говорим?
О разных... :) я о юзабилити. Подумайте. Ведь когда много "ответов", то родителя найти все равно вверх сновать и искать и времени займет ой как много...будет даже гараздо легче на страницу начажать предыдущую. Ничего страшного не случится, если разорвать, а вто выиграшь от этого гараздо больше. Хотя можно конечно по родителям paging-овать, но там будут трудности с запросом к БД. А делить в и-фейсе... можно но тогда потеряется корректный paging... хотя я смотрю например у youtube он как раз растягивающийся т.е. оконный... они не просчитывают count всего ... а просто делают "окно" с зазором на пару-пятеро страниц вперед. Посмотрите сами... Ну кто будет листать назад более 5 страниц? Скажите? Там не тупари сидят и всё уже давно просчитали. А получить весь count 10 лимонов записей... это уронит сервак на раз... хранить count в иерархической много нодовой БД... извините тоже запаришься считать...
Поэтому многие и делают как я его называю "оконный" paging...
правда youtube на нем и ставит точку на 5 странице, но никто не мешает делать плавающие окно.
Спасибо, пример с youtube немного изменил мою позицию.
Подскажите тогда вариант без рекурсии. Напомню, что у нас дерево, а не линейный массив.
А ты дерево прямо из sql-запроса получаешь? :)
Все комментарии к посту получаю одним sql-запросом, но в линейном виде. Потом преобразовываю в дерево.
Какой алгоритм выборки? неужеле вы не можете получить level коммента?
Выборка там простейшая, по id поста. Уровень могу получить. Но это уже не важно. Скорее всего, переделаю с использованием NS.
зачем по несколько раз инклудить одно и тоже?
Один из огромных минусов держать код в базе - это невозможность включать его в SVM (CVS).
На самом деле дамп тоже стоит держать в SVN, имхо удобно держать чистую и с не заюзаными тестовыми данными.
Кстати, да, можно попробовать. Спасибо!
С чего вы взяли, что eval может быть где-то выключено?
Пару раз стыкался с этим. Сейчас даже не вспомню на каких именно хостингах. В своё время перепробовал многие.
Вообще говоря принято вызывать представление в контроллере не более одного раза. Для этого вам придется в него передать все данные, а там уже разбирать. А множественный вызов представления противоречит MVC.
Сразу + . Вывод: уважаемый Apostol - переделывайте архитектуру. Ничего страшного в этом нет. Не занимайтесь фигней и тратой драгоценного времени.
Уважаемый Maxic, фигнёй никто не занимается. А вам минус в карму. Но ничего страшного, со временем научитесь вести дискуссии.
Уважаемый Apostol в 40 лет лет (повелись на ник? это ник моего сына, а их у меня уже 3-е :) ) я провел столько дисскусий и успешных переговоров с инвесторами, что вам скорее всего за ваш возраст (а по статистике здесь в основном возраст от 17 до 24) и не снилось. А вот насчет ошибки (а прогрмамированием, правда как хобби, я занимаюсь 18 лет уже), я её уже чувствую… тем более что я уже закончил свою cms с денормализованной унифицированной иерарархической БД, можно просто сказать как у вас — дерево, и никакой рекурсии там не надо в помине… дерево спокойно можно выбирать «линейно», существуют масса алгоритмов начиная от NS и заканчивая тем что я использовал (средние между NS и материализованным путем).
Поэтому еще раз советую — не занимайтесь хуней (другого слова уже тяжко подобрать, если сразу не понятно, я детей здесь не обидел, всем 18 есть?) Покажите ваш алгоритм, интересно, а вообще у вас есть блок-схема?
Только не надо говорить: конечно есть — сразу в студию…
Кстати слово рекурсия — это слово рекурсия… вы сами писали… и любая выборка в дереве рекурсией заканчивается полной фигней (читаем фактически это ошибка при проектировании «деревянных» БД, начиная от скорости, заканчивая стабильностью)… или кто-то не согласен и хочет получить кучу минусов :) спецы заминусуют сразу?
Вы много чего сказали по делу, и я за это благодарен. Но читать настолько эмоциональные посты, как этот, и тем более отвечать на них, нет желания. Извините.
Не обижайтесь, я просто злой человек, много "повидал" пережил. :)
А еще мне тяжело смотреть как люди бьются головой об лёд и теряют своё драгоценное время, которое стоит очень дорого, поэтому пытаюсь переубедить эмоционально.
В душе я добрый, особенно уважаю людей, признающих свои ошибки. Поэтому карму Вам улучшил. :)
А вообще, отвечу, не спадёт корона.

На ники и возраст внимания не обращаю, зря вы на этом внимание заострили. Хотя тоже начинаю чувствовать дискомфорт от того, что аудитория здесь молодеет и, соответственно, ухудшается качество материала и комментариев.

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

От рекурсий избавлюсь. Будем считать, что это было временным решением. Проект ещё не запущен, и я работаю над оптимизацией. Так что топик и его обсуждение оказались очень полезны. Всем спасибо!

Карму вам полечил. Стало даже лучше, чем было. ;)
Знаете я тоже всегда держу в голове всё, и бумажками не пользуюсь. На совещания всегда прихожу без ежедневника и никогда его не использую, но помню всё что проходило на совещаниях очень подробно. Нафига ж мозги и память природа дала. Но скажу честно... когда очень большой проект - очень удобно создать блок-схему... что я и делаю при больших проектах. Когда долго смотрите, на блок-схему, ошибки в проектировании выползают сами собой :) Просто поверь те моему опыту.
а можно посмотреть как "дерево спокойно можно выбирать "линейно""? ссылочку или пример плиз
Да, в моей системе шаблоны являются html+php (через ), и собсно я все цикли для такищ вещей выполняю уже внутри шаблона ( ), имхо так логичней
У меня эти самые вещи тоже происходят внутри шаблона.
Из контроллера у меня и вызывается один раз представление. В него передаётся всё дерево комментариев. Рекурсивно же вызывает контроллер сам себя для вывода вложенных комментариев.
А это еще хуже чем много раз представление вызывать. Ну скажу вам прямо - тупо для генерирования одной странице в цикле вызывать контроллер, который еще и гарантированно подгружает свое представление. Думайте над структурой. И если ваш фрэймворк весь основан на такой мягко говря неправильной архитектуре - то он нафиг никому не нужен. Так что думайте над архитектурой.
Да какой контроллер в цикле? :) Я этого не писал. Контроллер вызывается один раз. Из контроллера один раз вызывается представление. Представление, там где нужно отобразить вложенные комментарии и вложенные во вложенные и т.д., вызывает само себя и в качестве параметров передаёт только вложенные комментарии. Это самая обыкновенная рекурсия. Рекурсию можно осуществить в любом из существующих фреймворков, так что не надо додумывать на чём основан мой фреймворк. ;)
> ...Рекурсивно же вызывает контроллер сам себя для вывода вложенных комментариев.
и
> Представление, там где нужно ..., вызывает само себя

Вы уж решите, что у Вас там само себя вызывает.
Пардон, в предыдущем посте оговорился. Вызывает само себя представление.
Он выполняется только один раз, а нам содержимое представления нужно показать несколько раз.
Записал один раз в переменную и парси ее сколько хочешь.
У меня не парсер. В начале топика об этом написано. ;)
чем плох include_once()?
файл подключится при первом вызове и больше подключатся не будет...
Видимо тем что довольно медленная операция, не для цикла она придумана.
if(++$i<100){
include('view.php');
}

из этого следует, что подключается постоянно один и тот же файл. инклуд_ванс именно для этого и придуман. Он не будет подключать файл более чем один раз. один раз подключил и все. хоть в цикле, хоть без цикла. одно операция вместо 100 на каждую итерацию цикла. есть разница?
include_once придуман совсем не для этого(применения в циклах(это просто бред))
if(++$i<100){
include_once('view.php');
}
Он применяется восновном когда есть файлы включающие другие файлы, для все того же- чтобы не подгрузить по ошибке один файл много раз.
ну да. но если так рассуждать - то смысл этих рассуждений - практически нулевой) т.к. вообще изначально подход мягко говоря странный...
почему бы например не собрать все комментарии в один большой многомерный массив, а потом его одной функцией обработать и вывести уже...
я вообще использую XML+XSLT и не имею с деревьями никаких проблем ни по выводу, ни по скорости... :)
ну так бы нормальный человек и делал через массив. И ничего больше не надо(только в базе данных надо будет ввести поле еще одно, типа комментарий первого уровня)
А XML то тут причем, из массива уже можно выводить обычный HTML.
А XML тут при том, что я не делаю никаких массивов (ну не вообще, конечно, а так здоровенных "конечных"), а создаю сразу ДОМ объект xml'ьный, а потом его трансформером при помощи xslt превращаю во что мне нужно. Хоть в html, хоть в другой xml (rss, например)...
Разница есть — выведется только один комментарий. ;)
Да при чём здесь цикл? include_once подключит (и выполнит) файл только один раз, а нам его содержимое нужно показывать многократно.
Да притом что медленная операция include_once выполнится 100 раз, хоть файл подключится лишь однажды.
Нам нужно много раз, а не один, поэтому мы используем include, а не include_once. Циклы вторичны.
если у вас вид сделан html с php-вставками - стоит задуматься вообще...
если у вас вид сдела html - зачем тогда php?
Думать стоит всегда, даже перед тем, как просто что-то написать.
UFO just landed and posted this here
У нас дерево, а не линейный массив. Поэтому и используется рекурсия.
UFO just landed and posted this here
Знаем. Только для преобразования используется рекурсия. ;)
Но я понял на что вы намекали. Попробовать преобразовать так массив, чтоб он был пригоден для отображения дерева можно. Спасибо!
:))) расмешили. Вы вообще изучали/анализировали алгоритмы "выборки" деревьев....? NS слышали что это такое? Материализованный путь? есть и еще неплохие "коммерческие" алгоритмы для больших "деревянных" БД.
Вот маленький ликбез: http://phpclub.ru/faq/Tree/Ns
Выше отписался. Алгоритм буду менять. За ссылку спасибо. С материалом этим знаком, но раньше не видел причин для использования того, что там изложено.
я может немного не в теме или чего-то не понял, так сказать, для собственного развития, задам вопрос.
А почему не используются какие-либо шаблонизаторы, типа Smarty или подобных? Я так понимаю, что в системах шаблонов это реализовано. Или имеется ввиду именно реализация этой возможности в шаблонизаторе своей разработки?
До шаблонизатора еще дойти надо... там ошибка в контроллере, которая противоречит понятиям MVC.
Если придерживаться концепции MVC, то потом уже, с разруливанием данных, можно лепить что хочешь...
Где там, подскажите пожалуйста? ;) Вы понятия ведь не имеете как у меня выглядят контроллеры, модели и представления. Приведенные куски кода — только для тестирования.
eval("function rndf".rand(0,1000)."(){ $evalcodedata } ");
и поехали в цикле rndf231313()..

Если я не ошибаюсь - такое акселерируется
Выше подсказали про create_function. В неё можно засунуть include, и тогда точно акселерируется.
Не хотел бы я поддерживать проект, в котором вывод комментариев идет через eval...
CodeIgniter ;)
В своём фреймворке решил отказаться.
минус евала, что если ошибка, то скрипт падает . и это никак не отловить. по крайней мере я не смог, если отловите, то буду рад выслушать.
У меня наоборот ошибки чудесно показываются. Даже при ошибках парсера скрипт не вылетал. Настройки вывода ошибок — по умолчанию.
можно поподробнее ?
например
у меня eval ('fdfgdfgdgdfg'); вызывает ошибку и улетает (я канешно могу сделать ловилку ошибок), но хотелось бы прям в этом месте, типа try catch организовать.
Вставляю eval('fdfgdfgdgdfg'); в любом месте рабочего скрипта, получаю в этом месте вывод ошибки "Parse error: syntax error, unexpected $end in...". Всё остальное отображается как и раньше. Для отлова ошибки проверяйте что возвращает eval.
А вы лучше храните комментарии в виде дерева.
И одним запросом все заберете.
`Trees in SQL`: http://www.intelligententerprise.com/001…
`Storing Hierarchical Data in a Database`: http://www.sitepoint.com/print/hierarchi…
`Managing Hierarchical Data in MySQL`: http://dev.mysql.com/tech-resources/arti…
рабочий проект, но правда на Django тут http://code.google.com/p/django-mptt/
не проше хранить парента комента и при добавлении пересчитывать некий SortIndex(а вот он строиться циклически либо рекурсивно, но только при добавлении!)
Потом вывод сортировать по SortIndex и простейшими операциями изменять margin-left
соглашусь, расскажите только алгоритм построения этого индекса.
думаю, пригодиться
SELECT Id,ParentComment,timestamp ...
1.заливаем все в массив
while($r=$q->fetch_num())$ar[]=$r;
2.создаем один-большой-вложеный массив
while(Mapia_com_rewrite_in($da,$ar,$flat,$icc)){$icc++;}
3.гуляем по нему выставля индексы по порядку
array_walk($da,"Mapia_com_ufiller");
4.заливаем данные обратно( не забыть сделать это в транзакции)
foreach($mapia_com_filler as $key=>$value)....

где
function Mapia_com_ufiller(&$item,$key)
{
$mapia_com_filler[$key]=$mapia_com_filler_indx++;
array_walk($item,"Mapia_com_ufiller");
}

где
function Mapia_com_rewrite_in(&$da,&$inar,&$flat,$icc)
{
$nc=0;
foreach($inar as $key=>$r)
if(!isset($flat[$ar[0]]))
{
if($icc==0)
{
if($r[1]==0)
{
$da[$r[0]]=array();
$flat[$r[0]]=&$da[$r[0]];
unset($inar[$key]);
$nc++;
}
}
else
{
if(isset($flat[$r[1]]))
{
$flat[$r[1]][$r[0]]=array();
$flat[$r[0]]=&$flat[$r[1]][$r[0]];
unset($inar[$key]);
$nc++;
}
}
}
return $nc;
}

решение высосано из пальца минут так за 10 в электричке.
но оно работает, и работает быстро. Даже на больших обьемах данных.
Кто найдет баги - тому карму в плюс
UFO just landed and posted this here
Согласен... мало того а где хранить и самое главное зачем? в сессии? уродство... :)
Поэтому стройте дерево на основе level и сортировке сразу при запросе к БД и не заморачивайтесь...
а для ajax-а оставляем div id="parent_..от.." с display:none и добавляем новый коммент туда... с такими же пустыми div и т д
Все зависит от реализации, к примеру, в методе "Path Enumeration" пересчитывать дерево не придется.
UFO just landed and posted this here
В топике не заметили что eval не безопасен
В данном случае, на столько же не безопасен, как и include. ;)
У меня получились такие результаты:

include в цикле — 0.0004260
include_once в цикле — 0.000082688331
eval (получение кода до цикла) — 0.0002123594
мой_вариант — 0.0000336432456

Мой вариант — однажды подключение файла и потом вызов описанной в нем функции. Естественно, его минус это необходимость присваивать уникальные имена функциям.

Т.е. eval таки медленнее. Ну а остальные его плюсы для меня очень сомнительны (при хранении представления в БД, конечно, без него не обойтись, но это очень редкий случай)

> + Возможность кеширования кода представлений во фреймворке или шаблонизаторе
Совсем уж сомнительный плюс. Вы же не подключаете один и тот же кусок шаблона с одинаковыми параметрами?
1.Чуть выше посмотрите решение проблемы 1.
Евалом создаем рандом функцию, в которую и вставляем требуемый код.
Потом функцию вызываем.

По поводу последнего - какая разница какие параметры? кешируется байт код, а не дальше гдето по конвееру.
1. Как в такую функцию передавать параметры?
2. eval("function test".rand(0, 1111)."() { ?> <html> <?php } ");
не выводит и не возвращает ничего

По поводу последнего — мне показалось, что автор имел в виду кеширование уже итогового html
1. а чем такая функция отличается от обычных? Только ли способом своего создания.
2. это частности. Чего тама внутри и как это обрабатывать - собственное дело каждого.

3.По поводу последнего..хмм сложный вопрос. Кэширование вывода на этом уровне не логично. Проще весь блок кешануть.
Вроде как вопрос стоял о кэширование данных инклюда именно отображаемого элементика.
1. Вы не могли бы привести пример передачи в такую функцию, например, массива? Я действительно не могу понять как это сделать.
eval('function newrand_'.($nrand).'($r){'.$InStyle.'};');
.....
while($this->QResult->fetch())
{
...
call_user_func('newrand_'.($nrand),$r);
}
include_once в цикле выполнится ОДИН раз. Отсюда и такой выигрыш в скорости. В результате получаем, что eval БЫСТРЕЕ чем include, но медленнее чем вызов функции (кто бы сомневался).
Мдя... Сглупил. Не подумал, что include_once будет не только читаться, но и интерпретироваться только однажды.
>при хранении представления в БД, конечно, без него не обойтись
Почему, не обойтись? Напишите Stream Functions и пишите include 'db://moy-shablon.tpl';
Совет: храните комментарии в виде дерева. Я лучше чем Nested Sets не нашёл. Выборка из Nested Sets происходит одним запросом. Порядок следования элементов удобен для преобразования в древовидную структуру. Полученное дерево потом уже надо скармливать шаблонизатору. Шаблонизатор должен быть не настолько глупым, чтобы каждый раз делать include. Думаю, тут идеально подойдёт XSLT, хотя сам, признаюсь, всегда пользовался другими шаблонными движками.

P.S. Не мешайте HTML с PHP... Или мешайте, потом сами поймёте, почему лучше так не делать
Что ты имеешь ввиду когда говоришь не мешайте HTML c PHP? Полностью генерировать HTML из PHP или использовать только в слое представления?
Я имею в виду не использовать PHP в качестве шаблонизатора. И, соответственно, не делать ни include, ни eval.
почему это не стоит использовать PHP в качестве шаблонизатора? =) Просветите)
Так я Вам и рассказал =)
Для чего тут может подойти XSLT ? Вы предлагаете обработку дерева описать в XSL. И всё бы ничего, но где взять XML представление этого дерева, чтобы скормить XSLT процессору ? Уж не формировать ли через eval или include в цикле через PHP ?
Я думаю, что данные шаблонизатору надо передавать в конечном виде, а не в промежуточном. Если комментарии - древовидная структура, значит и передавать их надо в виде дерева. Я формирую древовидный PHP-массив за один проход, сформировать XML явно не сложнее. Возможно, создать дерево можно и непосредственно с помощью XSLT на основе ключей и XPATH, тут я не уверен. Я даже думаю, это менее верно.

Вообще, я долгое время был противником XSLT, сейчас же изменил своё мнение и активно изучаю его возможности. Вот почему: производительность железа быстро растёт, а XSLT, хотя и в разы медленнее Smarty, и, тем более Blitz, но позволяет лучше разделять данные от представления.
XSLT - НЕ шаблонизатор. XSLT - Extensible Stylesheet Language Transformations. XSL - язык расширяемых таблиц стилей. Ничего кроме парсинга и преобразования XML он не делает. XPath - язык запросов для выборки данных из дерева XML. XSL работает с XML и только с ним. Странно вообще, что вы умудрились сформировать какое-то мнение об XSLT (а тем более быть его противником), учитывая столь низкий уровень ваших знаний в нём =/
Вы представляете, я это знаю.
Но первый вариант в виде древовидной структуры будет такой:

<comment id="1">
    <comment id="2"></comment>
</comment>

А в плоском виде какой-то такой:

<comment id="1" level="0" left_key="1" right_key="4"/>
<comment id="2" level="1" left_key="2" right_key="3"/>

Как собирать из него дерево, я не знаю. И XPath тут наерно пригодится )))
Если будет происходить часто вставка комментариев, то НестедСетс не лучший выбор - согласен, что выборка очень удобно, но операция вставки (и удаления/перемещения) довольно ресурсоемкие
С перемещением, пожалуй, соглашусь. На добавление, в целом, уходит 4 запроса. Для таких проектов как Хабр и Автокадабра использование Nested Sets вполне оправдано
«Права купил, ездить не купил».
eval — костыль для крайних случаев. Код каждый раз заново компилируется, ничего удивительного, что тормозит.
include можно делать хоть из переменной (см. stream_wrapper_register). Правда, акселератор тогда может и не помочь.
include по сто раз за раз — не круто.
За "остроумие" — минус в карму. Если бы вы потрудились глянуть на время выполнения тестов, то увидели бы, что eval тормозит как-раз меньше, чем include. И код "компилируется" каждый раз в обоих случаях, если не использовать внешние акселераторы.
Методику подсчетов в студию. Параметры стенда, количество выполненных тестов, погрешности измерений (точность до микросекунд? Не верю!). В противном случае эти подсчеты ничего не стоят: все полученные результаты имеют один порядок и при другом положении звезд на небе очень сильно поменяются.
Для меня важно было приблизительное соотношение времени выполнения различных методов, а не точность до микросекунд. Если вам нужны подробности, то вкратце — microtime(), php5, apache2, centos, сервер 64-битн., 2ГБ. На виндовой машине цифры были другие, и соотношения немного отличались, но смысл тот же.
Ну так и пишите приблизительно, безо всяких микросекунд. Сразу станет понятно, что это не та часть программы, где можно выиграть много времени.
Почему вы вообще решили оптимизировать именно эти вызовы? Вы запускали профайлер?
Да пожалуйста, мне не жалко. Рад, что доставил Вам удовольствие. Надеюсь, и пользу принесу.
А если include делать по сети, то eval ещё быстрее будет. Удивительно, правда?
Что значит — «если не использовать внешние акселераторы»? Если мы не используем акселератор, значит, скорость нас не интересует.
и т.д. что у вас там незнаю еще...
что-то как-то все уж больно сложно у вас :)

я бы сделал примерно так:

комментарии храним в таблице в ввиде
comment_id | parent_id | body
, где:
comment_id - ID комментария
parent_id - ID родительского комментария
body - содержимое комментария
created - время добавления комментария
....

// далее вытаскиваем комментарии из базы:
$result = mysql_query("SELECT * FROM comments ORDER BY created");
if (mysql_num_rows($result) > 0) {
while ($row = mysql_fetch_array($result)) {
$comments[] = $row;
}
}

// далее рекурсивная функция строющая дерево комментов
function getTreeArray(&$list, $k = 0)
{
for ($i=0; $i '.file_get_contents('view.php').'
фу ты блин... коммент испоганился... вот правильный вариант функции:
/ далее рекурсивная функция строющая дерево комментов
function getTreeArray(&$list, $k = 0)
{
for ($i=0; $iфу ты блин... коммент испоганился... вот правильный вариант функции:
/ далее рекурсивная функция строющая дерево комментов
function getTreeArray(&$list, $k = 0)
{
for ($i=0; $iфу ты блин... коммент испоганился... вот правильный вариант функции:
/ далее рекурсивная функция строющая дерево комментов
function getTreeArray(&$list, $k = 0)
{
for ($i=0; $iфу ты блин... коммент испоганился... вот правильный вариант функции:
/ далее рекурсивная функция строющая дерево комментов
function getTreeArray(&$list, $k = 0)
{
for ($i=0; $i
спор из разряда:
что быстрее ECHO или PRINT...
а рекурсия зло, независимо от того с include она или c eval.
что тут обсуждать вообще?
Почему это рекурсия - зло? Откуда такая однозначность?
несмотря на квази-красоту кода при ее использовании, переполнение стека и забивание памяти не так уж трудно вызвать. к тому же практически всегда можно сделать тоже самое, но без рекурсии, а просто изменив алгоритм.
Думаю, надо быть ближе к реальности. Одно дело поиск пути в огромном графе, другое - комментарии, где глубина вложенности ограничевается здравым смыслом - 6-10 максимум.
Никогда не пишите рекурсивный eval. Лучше вообще на год или два забудьте про него, потому что оптимальность и безопасность там не стоят и близко. Прежде чем изобретать свой механизм генерации комментариев, посмотрите, как они сделаны в других фреймворках — все уже придумано десять лет назад.

Еще рулит матчасть. Почитайте любую классическую книжку по алгоритмам, обход дерева (как и любую другую рекурсивную процедуру) всегда можно описать без рекурсии.
Написали всего много, давайте теперь обратимся к теории

Что делает PHP интерпретатор когда встречает include?
ответ:
1. парсит код
2. строит дерево связей сущностей (мапинг адресов переменных и констант, деклараций классов и функций)
3. изменяет дерево исполнения.
4. исполняет.

что происходит при повторном подключении?
PHP смотрит на адреса при смене контекста и исполняет байт код собранный ранее. (если файл не меняли)

что происходит при повторном исполнении инклюда?
дерево связий есть, таблица адресов тоже, байт код даже есть, так что копируется кусок байт кода, подготовленного ранее и все (кстати в PHP4 глюки на этой почве народ ловил ^_^).

Теперь что произойдет при eval ??
тоже самое что и в случае с инклюдом, тока откроется внутренний поток ошибок.

что же происходит при повторном вызове eval ??
интерпритатор не может строить предполодений на природу кода который передан в eval поэтому проводит ВСЕ шаги заново.

Как меняет ситуацию акселератор?
в случае если у вас в подключаемом файле есть например такая конструкция echo "this"." my "." file" акселератор может заменить это на константу, убрать операции контененации, т.е. все стандартные фишки акселерации. В случае с eval код через акселератор не пропускается.

теперь по поводу эксперимента привыкайте писать условия: какая машинка, какая ось, а то странный и не воспроизводимый результат. и число измерений повысить ИМХО стоит ибо тысячные секунды могут встять из-за таких факторов как процессорная оптимизация, влезло или нет в кеш проца и прочие.
Так как с внутренними процессами в интерпретаторе и акселераторе я знаком только поверхностно, для меня важнее были результаты тестов. Тесты провел на сервере с линуксом и на домашней виндовой машине. Цифры, нонечно разные, и смысла в точности нет. Но соотношение времени выполнения исследуемых методов приблизительно одинаковое было на обеих машинах. Те цифры, что опубликованы, получены на 64-битн. сервере, 2ГБ, centos, apache2, php5.
Apostol написал...
> Когда пришлось реализовывать дерево комментариев, столкнулся с необходимостью рекурсивного вызова представления (view в MVC)
Зачем рекурсия ... это противоречит концепции MVC.
Получите ВСЕ данные, а потом в View их "разруливайте" ... т.е. получаете выборкой из БД (NS или подобные) ВСЕ данные дерева, где один из параметров будет level (постороить дерево потом это 10 класс средней школы), можете их потом обработать модулями или еще какой-нибудь хренью... и спокойно выводите их ... причем как хотите, и любыми шаблонизаторами...
Вывод: или вы не правильно употребили слово "рекурсия" или что-то не так делаете...
Данные и так получаю все одним запросом. Но алгоритм буду менять. Не зря всё-таки создал этот топик. ;)
А require использовать не пробовали? Он, в отличие от include файлы компилит один раз и кеширует.
require от include не отличается ничем, кроме ошибки при отсутствии файла (fatal/warning соответственно).
Nested Set с дырками даст все что нужно, либо обычное дерево с парент айди и датой коммента и левелом отсортировтаь по дате и сдвинуть на левел
UFO just landed and posted this here
Sign up to leave a comment.

Articles

Change theme settings