За последние 24 часа нас посетили 22214 программистов и 1077 роботов. Сейчас ищут 704 программиста ...

Идея алгоритма обработки результатов из базы

Тема в разделе "Решения, алгоритмы", создана пользователем Psih, 30 сен 2010.

  1. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Меня давно мучает этот паттерн:

    Код (Text):
    1.  
    2. Запрос на базу
    3. В случае библиотеки часто делается массив
    4. Массив обрабатывается в пользовательском коде (htmlspecialchars и прочее, когда простое, когда сложное)
    5. Скармливаем шаблону и он это всё раскручивает в цикле опять для вывода.
    В итоге имеем 2 или 3 цикла.
    А что если заюзать лямбда-функции PHP 5.3? При составлении запроса составляем массив вида array('field' => function ($field) {}, 'field2' => function ($field) {}, ....). Метод выборки генерирует объект, который мы передаём в шаблон и там его раскручиваем как обычный массив (т.е. это должен быть итератор я так понимаю). Все escape & co выполняются прямо на лету.

    Правда работает не всегда, т.е. это должен быть отдельный метод, типа $db->queryIterator() (имя надо придумать, пока в голову не пришло).

    Discuss?!
     
  2. admyx

    admyx Активный пользователь

    С нами с:
    14 мар 2008
    Сообщения:
    2.159
    Симпатии:
    1
    Подожди-подожди. Я не очень понял
    Давай, для примера, возьмем смарти.
    PHP:
    1.  
    2. <?php
    3. $DB->select(array('select' => 'data', 'from' => 'table'));
    4. $OUT->assign('someData', array());
    5. while($d = $DB->fetch())
    6.     $OUT->append('someData', $d);
    Раз крутим, так?

    Потом в шаблоне
    {foreach key=key item=d from=$someData}
    {/foreach}
    Два крутим.

    А как ты предлагаешь, объясни больше, пожалуйста.
     
  3. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Либо так же через foreach (если это Iterator + ArrayObject) либо while ($v = $dataObject->fetch()): .... endwhile;
     
  4. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    В порядке бреда:
    Передавать в шаблон некий объект инкапсулирующий в себе ресурс.
    PHP:
    1. <?php
    2. $res=$db->query($sql);
    3. $res->setFetchMethod(MyResourse::ASSOC);
    4. $myTpl->arrData=$res;
    5.  
    PHP:
    1. <?php
    2. class MyResourse implements Iterator{
    3. ...
    4. protected function getRes(){
    5.     if (!this->res){
    6.         $this->res=$this->db->query($this->query);
    7.     }
    8.     return $this->res;
    9. }
    10.  
    11.     public function current (){
    12.         return $this->row;
    13.     }
    14.  
    15.     public function key (){
    16.         return $this->key;
    17.     }
    18.  
    19.     public function next ( void ){
    20.         $res=$this->getRes();
    21.         $fetchMethod=$this->fetchMethod;
    22.         $this->row=$this->db->$fetchMethod($res);
    23.         $this->key++;
    24.     }
    25.  
    26.     public function rewind (){
    27.         $this->res=null;
    28.     }
    29.  
    30.     public function valid ( void ){
    31.         return (bool)$this->row;
    32.     }
    33.  
    34.  
    35. }
    Тогда и запрос можно посылать лениво (хотя вряд ли оно особо надо).
     
  5. lexa

    lexa Активный пользователь

    С нами с:
    22 июл 2007
    Сообщения:
    1.746
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Некоторые шаблонизаторы так и делают - работают с объектом. Ну, в контексте какой-то системы, конечно.

    Вроде в http://wiki.limb-project.com/ так. Давно его копал, точно не помню.
     
  6. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    1. Зачем каждому полю по лямбде? Можно одну лямбду, которая обрабатывает одну запись.
    2. Чем плохи 2-3 цикла? Программисту придётся реализовывать каждый раз только от 0 до 1, остальные два внутри библиотеки БД и шаблонизатора.
    Производительностью? Пользовательский итератор и лямбды будут намного медленнее даже 3-х циклов по встроенным типам данных.
     
  7. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    Да, и как же:
     
  8. Volt(220)

    Volt(220) Активный пользователь

    С нами с:
    11 июн 2009
    Сообщения:
    1.640
    Симпатии:
    1
    Самое главное забыл:
    У $res надо устанавливать callback и в next его вызывать.
     
  9. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    я делал и без лямда функций через обычные магические методы, тобишь как бы в шаблонизаторе происходил фетч. Отказался потом, что мне надо было делать фетч всего до того, как шаблонизатор вообще начнет присутствовать ибо prepare -> stmt механизм не позволяет не последовательно пользоваться stmt...
    А делалось всё просто - итератор надо mysqli_result, над ним коллекция, тоже итератор, с ленивым __get
     
  10. admyx

    admyx Активный пользователь

    С нами с:
    14 мар 2008
    Сообщения:
    2.159
    Симпатии:
    1
    Костян
    Кость, а нафиг шаблонизатору иметь дело с БД напрямую о_0
     
  11. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    admyx
    не на прямую, шаблонизатор имеет дело с коллекцией, фактически внутри него эта коллекция массив, а данные проходят через преобразования в каком-то методе, типа _onGetLogin в самом __get...
    Да и вообще тут
     
  12. admyx

    admyx Активный пользователь

    С нами с:
    14 мар 2008
    Сообщения:
    2.159
    Симпатии:
    1
    Костян
    Пыщь, дык мы и дискутируем =)

    Хз. конечно.
    Что у IPB, что у меня (ну ты помнишь) шаблонизатор играет только свою роль
     
  13. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    прикол в том, что когда я не пробежал в коллекции по всем элементам, и попользовался второй коллекцией, то в первой на фечнутые данные я потерял. Так как я хочу прозрачно обращаться к коллекциям в разные моменты времени, то надо делать фечь всем результатам и класть в буфер, а это способствует появлению нового массива и нового цикла. Последнее удобнее, потому что оно намного проще и понятнее и не надо тут ничего придумывать.
     
  14. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Что плохого в 2-3-10 циклах ?

    Разница между
    PHP:
    1. <?php
    2. for($i=0; $<100; $i++) {
    3.     $a = $b;
    4.     $b = $a;
    5. }
    6. ?>
    и
    PHP:
    1. <?php
    2. for($i=0; $<100; $i++) {
    3.     $a = $b;
    4. }
    5. for($i=0; $<100; $i++) {
    6.     $b = $a;
    7. }
    8. ?>
    совершенно несущественная (не проверял, но теоретически)
     
  15. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    у меня тоже он играл такую же роль, но он оперировал коллекциями так, что надо было 2 записи из одной коллекции 2 из другой, следующие 2 из одной, потом опять из другой.... И всё, вся малина при этом уходила, и выводилось всего лишь 4 записи, потому что коллекции не рассчитаны были на такое обращение... От такие дела!
     
  16. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    Vladson
    ну чисто теоретически там будет:
    PHP:
    1. $i++
    2. $i < 100 ?
    3. $a = $b
    4. $b = $a
    против
    PHP:
    1. $i++
    2. $i < 100 ?
    3. $a = $b
    4. $i++
    5. $i < 100?
    6. $b = $a
     
  17. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Vladson
    В данном случае не очень хороший пример, потому что когда мы вытаскиваем данные из ресурса, они копируются в массив. Ну и у тебя просто переменные содержащие 1 элемент.

    Смысл в снижении накладных расходов на циклы + там всё же логика по сложнее будет.

    Обычно выглядет так (схематично)
    PHP:
    1. <?php
    2. $res = $db->query($sql);
    3. $array = array();
    4. while ($row = $res->fetch_assoc()) {
    5.     $array[] = $row;
    6. }
    7.  
    8. // .....
    9. $data = array();
    10. foreach ($array as $row) {
    11.     $row['title'] = htmlspecialchars($row['title']);
    12.     $row['user'] = getUserById($row['user']);
    13. }
    14. $tpl->set('data', $data);
    15.  
    16. // ......
    17.  
    18. foreach ($data as $v):?>
    19.     <div class="item">
    20.         <h3><?php echo $v['title']?></h3>
    21.         <span class="user">
    22.             <?php echo $v['user']?>
    23.         </span>
    24.     </div>
    25. <?php echo endforeach;?>
    26.  
    А мысль в том, что бы свести это к (схематично)
    PHP:
    1. <?php
    2. $obj = $db->query($sql, array(
    3.     'title' => function ($field) { return htmlspecialchars($field); },
    4.     'user' => function ($field) { return getUserById($field); }
    5. ));
    6.  
    7. $tmp->set('obj', $obj);
    8. // ....
    9.  
    10. foreach ($obj as $v):?>
    11.     <div class="item">
    12.         <h3><?php echo $v->title?></h3>
    13.         <span class="user">
    14.             <?php echo $v->user?>
    15.         </span>
    16.     </div>
    17. <?php echo endforeach;?>
    18.  
    В момент вывода в шаблоне вызываются лямбды и возращают данные.

    Да, я понимаю что это не везде применимо, это дополнительный функционал к стандартным. Просто часто бывает вывод ограничивается тем, что выбрали из базы, эскейпнули и вывели в шаблон. В этих случаях будет убыстрение и упрощение кода даже.
     
  18. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    Я продолжаю настаивать, что итераторами и лямбдами снижения наклодных расходов по сравнению с циклами не добиться. Хотя в соседней теме меня обвиняли в байтодрочестве.
     
  19. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    А я продолжаю настаивать, что смысла в этом нет, это можно сделать просто типизировав объект $obj и написав нужное в событиях при чтении свойств, хотя задумка тоже ничего...
     
  20. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    vasa_c
    Дело не тока в накладных расходах, есть ещё уменьшение и упрощение кода :)

    Мну лично конкретно достало строчить шаблон вида "Запрос -> Оработка запроса -> Эскейп данных -> Отдать в шаблон -> В шаблоне развернуть в цикл". В идеале хочу " Запрос -> В шаблон -> Вывел" :)

    Как это будет выглядеть и работать я вам не говорю, тут каждый думает сам :)
     
  21. admyx

    admyx Активный пользователь

    С нами с:
    14 мар 2008
    Сообщения:
    2.159
    Симпатии:
    1
    Костян
    А я психа поддерживаю.
    Меня тоже заебало.
    Правда, я решил введением дополнительного метода в ядро.

    PHP:
    1. <?php
    2.         $this->e->DB->select(array('select' => 'name, url',
    3.                         'from'  => 'core_pages',
    4.                         'where' => $where
    5.                     ));
    6.         $this->e->toOUT('childrens');
     
  22. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    Psih
    бесспорно инъекции лямбда функций это круто, и может быть достаточно эффективнми во многих местах... Только вот у меня эскейп данных в основном происходит в шаблоне... Всё рано ты получишь то же самое, ну может меньше писать будешь...
     
  23. MiksIr

    MiksIr Активный пользователь

    С нами с:
    29 ноя 2006
    Сообщения:
    2.340
    Симпатии:
    44
    А я вот, ради разнообразия, буду настаивать, что в случаях когда замена нескольких циклов на один принесет хоть чуточку заметный профит - эту часть приложения нужно переписывать на С. А написанное на PHP должно в первую очередь быть приятным для чтения и модификации, и в последнюю - оптимизировать быстродействие. Вот такой холивар.
     
  24. Padaboo

    Padaboo Старожил
    Команда форума Модератор

    С нами с:
    26 окт 2009
    Сообщения:
    5.242
    Симпатии:
    1
    меня за такие предложения наркоманом обзывали :)
     
  25. vasa_c

    vasa_c Активный пользователь

    С нами с:
    22 мар 2006
    Сообщения:
    1.760
    Симпатии:
    0
    Адрес:
    гор.Ленинград
    Лямбда-функция на каждое поле, не уверен, что упростит код, но не буду упорствовать.

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

    имхо, это дело шаблона. Ну и по всякому эскейп нужно прописывать в лямбде.

    Отдавать придётся по-всякому

    Ну и разворачивать в цикле итератор также придётся, как и массив.