За последние 24 часа нас посетили 19118 программистов и 1644 робота. Сейчас ищут 918 программистов ...

Замыкание в PHP, мозгошторм

Тема в разделе "Прочие вопросы по PHP", создана пользователем jora, 16 сен 2013.

  1. jora

    jora Новичок

    С нами с:
    9 сен 2013
    Сообщения:
    19
    Симпатии:
    0
    Помогите докумекать

    Есть вот такой вот код (часть класса)
    Код (Text):
    1.  
    2.     protected $q;
    3.  
    4.     public function query($query) {
    5.         $this->q=$this->db->query($query);
    6.         return $this->q;
    7.     }
    8.  
    9.     public function fetch_object() {
    10.         if(!is_object($this->q)) {
    11.             return false;
    12.         }
    13.         return $this->q->fetchObject();
    14.     }
    Вот так используется и все работает нормально


    Код (Text):
    1. if($this->db->query("SELECT * FROM `blog`;") {
    2.     while($row = $this->db->fetch_object()) {
    3.        
    4.     }
    5. }
    Но если сделать вложенность, то ничего работать не будет

    Код (Text):
    1. if($this->db->query("SELECT * FROM `blog`;") {
    2.     while($row = $this->db->fetch_object()) {
    3.         if($this->db->query("SELECT * FROM `comment`;") {
    4.             while($row_x = $this->db->fetch_object()) {
    5.                
    6.             }
    7.         }
    8.     }
    9. }
    Все дело в $this->db->q в которой сохраняется ссылка на обьект

    В общем нужно как то применив замыкание сделать $this->q для каждого вызова функции query свою
     
  2. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    сколько умных слов и говнокод. =) не проще выбрать сначала все блоги, потом все коменты, потом отрисовать. А то миллион запросов к бд делать это капец.
     
  3. jora

    jora Новичок

    С нами с:
    9 сен 2013
    Сообщения:
    19
    Симпатии:
    0
    Вопрос не о говнокоде а об вопросе замыкания
    Этот код я набросал только что чтобы было понятно о чем идет речь
    Никаких блогов я не программирую
    Тем более если так программировать блог ничего не выйдет
    Данный код скорее нужен для построения дерева
    В javascript очень часто пользуюсь замыканиями, тут же все по другому
     
  4. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    окей. ты хочешь спросить, как можно получить типа такое, если у тебя объект-коннект один.

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

    Часть затер, ибо суть теряется. так что будут вопросы - задавай.

    да не в замыканиях дело. В js у тебя была бы точно такая же ситуация.

    недавно была статейка на хабре. я в деревьях не шарю, так что помочь не смогу. но точно знаю, что тема избитая. Одно точно, дерево выбирается одним запросом, потом формируется на стороне клиента уже в реальное дерево. Гонять по однму запросу - смерть.
     
  5. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.819
    Симпатии:
    1.333
    Адрес:
    Лень
    у тебя идет замыкание изза гавнокода.. кто так берет в цикле внутри и запрашивает бд???
     
  6. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    он же написал, что это просто пример.
     
  7. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.819
    Симпатии:
    1.333
    Адрес:
    Лень
    но даже пример збс
     
  8. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    и кстати да, это один из самых распространенных случаев говнокода. частенько встречается в магазинах или в цмсках с кучей модулей.
     
  9. jora

    jora Новичок

    С нами с:
    9 сен 2013
    Сообщения:
    19
    Симпатии:
    0
    Вот теперь вы подобрались к тому почему я задал этот вопрос =)
    Найдет 1 чувак из 100 который заюзает вот именно так тулзу как написано выше
    Я пишу тулзу для работы с базой
    В конфиге я могу написать допустим pdo, mysqli, mysql и т.д. и сайт не порушится и ничего переписывать в коде не придется
    Пока я экспериментировал увидел что не плохо было бы вначале проверять выполнился ли запрос
    потом вытаскивать обьект или массив и потом с ним работать, потом вспомнил обычный старый драйвер mysql, ну типа как в книжках пишут
    Вспомнил что там бы код был примерно таким

    Код (Text):
    1. $q=$this->db->query("SELECT * FROM `blog`;")
    2. if($q) {
    3.     while($row = $this->db->fetch_object($q)) {
    4.        
    5.     }
    6. }
    И тут я подумал а зачем создавать новые переменные...
    И собственно упростил как написал в первом посте
    И стал думать как реализовать
     
  10. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    я использую свой класс для работы с бд. Он не такой как пдо, и не за тем, т.е. не велосипед. Однако он мне очень удобен и полезен. Что он делает. Отдает массив. Там есть несколько методов, которые работают чуток по-разному. Но суть одна - отдает массив. Это тот подход, что я описал вышел. Сделал запрос, разобрал, отдал. Не важно, массив ты возвращаешь, некий объект, или еще что. Суть ясна.

    Однако. Недавно в пхп были введены итераторы. Т.е. ты можешь держать в памяти внутри экземпляра класса кучу ответов, выдавая строки по-одной, принимая однако в качестве аргумента идентификатор. В данном случае можно создать такой алгоритм, что он будет держать в памяти объекты-ответы из БД, которые не жрут память пхп в отличие от массивов. но тут я не поручусь за время их жизни - раз, и два, ограничение памяти пхп представляет проблему только на мелком хостинге, а на таком хостинге клиенты не особо морочатся вообще ни чем.

    Добавлено спустя 3 минуты 57 секунд:
    а что тебя пугает? в данном случае память уже отожрана, и отжрана скорее всего не в зачет пхп, так что не парься. Помни что при использовании родного мускульного водителя и некоторых методов, возвращающих массив без цикла, память будет жориться уже в зачет пхп.
     
  11. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Блин, а не кто не замечает, что человек поле $q перезаписывает, а потом по нему же цикл пытается делать. Ну то есть берётся запрос блогов, mysqli_result пишется в переменную $this->db->q, и идёт цикл по всем результатам с помощью метода $this->db->fetch_object(), использующего как раз $this->db->q. Пока ОК. Потом делается запрос комментов, и класс с базой данных (ведь экземпляр-то тот же!) премиленько пишет его (запроса по комментам) mysqli_result в то же самое поле $this->db->q, после чего идёт прогон цикла по всем комментам, и, соответственно, $this->q приходит к конечному состоянию, когда $this->db->q->fetch_object() возвращает null. И тут происходит попытка новой итерации цикла по блогам, естественно она не проходит.
     
  12. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    ну вот как бы об этом и топик вроде :D
     
  13. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Тут все говорят о том, что он отдельными запросами берёт блоги и их комменты, и это неэффективно с точки зрения работы с БД. Но не работает код не поэтому, а потому что человек вложенный цикл ведёт по той же переменной, что и внешний!
     
  14. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    ну он с этим вопросом и пришел.
     
  15. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Ха, в качестве дурости - сделать $q массивом mysqli_result... И стандартные функции для организации стека использовать... Работать будет. Хотя лучше другое решение найти... Я вот захотел в качестве саморазвития с нуля написать CMS, и только утром почти такую же ошибку сделал - класс для работы с DB хотел сделать одновременно итератором результата. Но одумался, разделил на два класса :)
     
  16. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    вот и расскажи, почему ты считаешь это ошибкой.
     
  17. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Потому что часто бывает ситуация, когда результат одного запроса нужно использовать в другом, причём во вложенных циклах в том числе. И заводить несколько экземпляров класса базы данных для этого - это какое-то извращение получается. А вот несколько экземпляров итератора результата - самое оно :)
     
  18. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    А почему кстати не отдавать сразу массив? Благо это делается одной функцией нейтив драйвера.
     
  19. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    А мне, кстати, реально попался как-то хостинг, на котором вызов mysqli_result::fetch_all() не проходил... php говорил, что нет такого метода. Пришлось самому писать
     
  20. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    ну короче изложу мысль. если отдавать в массиве, то это будет отжирать память пхп, объем которой регламентируется в настройках. А если отдавать привычный итератор - то не будет. Так что это дело выбора.
     
  21. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Тем, кто не хочет создавтаь экземпляры классов для работы с БД для каждого запроса посвящается.

    1) Ребят, не велосипедируйте и не издевайтесь над собой и машиной, пытаясь решить проблему, которой нет.
    2) Ребят, не городите ООП там, где можно прекрасно жить без него.
    3) В PHP легко гибридизирутются ООП и процедурный стили. Это нормально. Не извращение, не говнокод. Даже ваша операционная система, например, полностью процедурная на низком уровне. Иначе быть не может. А на высоком уровне уже объекты.
    4) Боитесь гибридного подхода - юзайте статический класс для БД.

    У меня, к примеру, в движке 100% процедурное ядро. Просто потому что нет смысла его делать объектным. Почему не статик? Потому что оно не монолитное и состоит из независимых фрагментов, подгружаемых в lazy-режиме. Для БД тоже отдельный фрагмент, разумеется. Все функции, которые нужно отдать наружу, агрегируются через статический API-класс в виде API::псевдонимов. При этом все внешние модули и компоненты в обязательном порядке являются объектами. При этом все работает четко, быстро и очень аккуратно расходует оперативу на запрос.

    Я уже не первый раз форсю тут одну из заповедей разраба - не делай что-то только ради того, чтобы оно было. ООП ради ООП, код ради кода. Если ООП пришло в PHP сравнительно недавно, это не значит что оно лучше процедурного подхода. А процедурный подход не хуже ООП. Молоток не лучше гаечного ключа. Гаечный ключ не лучше дрели. Но дырку в стене лучше делать именно дрелью, а не гаечным ключом. У каждого инструмента свое назначение.
     
  22. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    согласен.

    ЗЫ: крепко сижу на статике в большинстве случаев. Но не всегда.