Помогите докумекать Есть вот такой вот код (часть класса) Код (Text): protected $q; public function query($query) { $this->q=$this->db->query($query); return $this->q; } public function fetch_object() { if(!is_object($this->q)) { return false; } return $this->q->fetchObject(); } Вот так используется и все работает нормально Код (Text): if($this->db->query("SELECT * FROM `blog`;") { while($row = $this->db->fetch_object()) { } } Но если сделать вложенность, то ничего работать не будет Код (Text): if($this->db->query("SELECT * FROM `blog`;") { while($row = $this->db->fetch_object()) { if($this->db->query("SELECT * FROM `comment`;") { while($row_x = $this->db->fetch_object()) { } } } } Все дело в $this->db->q в которой сохраняется ссылка на обьект В общем нужно как то применив замыкание сделать $this->q для каждого вызова функции query свою
сколько умных слов и говнокод. =) не проще выбрать сначала все блоги, потом все коменты, потом отрисовать. А то миллион запросов к бд делать это капец.
Вопрос не о говнокоде а об вопросе замыкания Этот код я набросал только что чтобы было понятно о чем идет речь Никаких блогов я не программирую Тем более если так программировать блог ничего не выйдет Данный код скорее нужен для построения дерева В javascript очень часто пользуюсь замыканиями, тут же все по другому
окей. ты хочешь спросить, как можно получить типа такое, если у тебя объект-коннект один. Вот тогда делай как я сказал, не читай часть про говнокод. Выбираешь блоги или что там у тебя. Потом обрабатываешь ответ. Сразу. Складываешь в масси например, или объект отдельный создаешь через это. Короче не важно. А только потом уже лезешь в базу снова. Часть затер, ибо суть теряется. так что будут вопросы - задавай. да не в замыканиях дело. В js у тебя была бы точно такая же ситуация. недавно была статейка на хабре. я в деревьях не шарю, так что помочь не смогу. но точно знаю, что тема избитая. Одно точно, дерево выбирается одним запросом, потом формируется на стороне клиента уже в реальное дерево. Гонять по однму запросу - смерть.
и кстати да, это один из самых распространенных случаев говнокода. частенько встречается в магазинах или в цмсках с кучей модулей.
Вот теперь вы подобрались к тому почему я задал этот вопрос =) Найдет 1 чувак из 100 который заюзает вот именно так тулзу как написано выше Я пишу тулзу для работы с базой В конфиге я могу написать допустим pdo, mysqli, mysql и т.д. и сайт не порушится и ничего переписывать в коде не придется Пока я экспериментировал увидел что не плохо было бы вначале проверять выполнился ли запрос потом вытаскивать обьект или массив и потом с ним работать, потом вспомнил обычный старый драйвер mysql, ну типа как в книжках пишут Вспомнил что там бы код был примерно таким Код (Text): $q=$this->db->query("SELECT * FROM `blog`;") if($q) { while($row = $this->db->fetch_object($q)) { } } И тут я подумал а зачем создавать новые переменные... И собственно упростил как написал в первом посте И стал думать как реализовать
я использую свой класс для работы с бд. Он не такой как пдо, и не за тем, т.е. не велосипед. Однако он мне очень удобен и полезен. Что он делает. Отдает массив. Там есть несколько методов, которые работают чуток по-разному. Но суть одна - отдает массив. Это тот подход, что я описал вышел. Сделал запрос, разобрал, отдал. Не важно, массив ты возвращаешь, некий объект, или еще что. Суть ясна. Однако. Недавно в пхп были введены итераторы. Т.е. ты можешь держать в памяти внутри экземпляра класса кучу ответов, выдавая строки по-одной, принимая однако в качестве аргумента идентификатор. В данном случае можно создать такой алгоритм, что он будет держать в памяти объекты-ответы из БД, которые не жрут память пхп в отличие от массивов. но тут я не поручусь за время их жизни - раз, и два, ограничение памяти пхп представляет проблему только на мелком хостинге, а на таком хостинге клиенты не особо морочатся вообще ни чем. Добавлено спустя 3 минуты 57 секунд: а что тебя пугает? в данном случае память уже отожрана, и отжрана скорее всего не в зачет пхп, так что не парься. Помни что при использовании родного мускульного водителя и некоторых методов, возвращающих массив без цикла, память будет жориться уже в зачет пхп.
Блин, а не кто не замечает, что человек поле $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. И тут происходит попытка новой итерации цикла по блогам, естественно она не проходит.
Тут все говорят о том, что он отдельными запросами берёт блоги и их комменты, и это неэффективно с точки зрения работы с БД. Но не работает код не поэтому, а потому что человек вложенный цикл ведёт по той же переменной, что и внешний!
Ха, в качестве дурости - сделать $q массивом mysqli_result... И стандартные функции для организации стека использовать... Работать будет. Хотя лучше другое решение найти... Я вот захотел в качестве саморазвития с нуля написать CMS, и только утром почти такую же ошибку сделал - класс для работы с DB хотел сделать одновременно итератором результата. Но одумался, разделил на два класса
Потому что часто бывает ситуация, когда результат одного запроса нужно использовать в другом, причём во вложенных циклах в том числе. И заводить несколько экземпляров класса базы данных для этого - это какое-то извращение получается. А вот несколько экземпляров итератора результата - самое оно
А мне, кстати, реально попался как-то хостинг, на котором вызов mysqli_result::fetch_all() не проходил... php говорил, что нет такого метода. Пришлось самому писать
ну короче изложу мысль. если отдавать в массиве, то это будет отжирать память пхп, объем которой регламентируется в настройках. А если отдавать привычный итератор - то не будет. Так что это дело выбора.
Тем, кто не хочет создавтаь экземпляры классов для работы с БД для каждого запроса посвящается. 1) Ребят, не велосипедируйте и не издевайтесь над собой и машиной, пытаясь решить проблему, которой нет. 2) Ребят, не городите ООП там, где можно прекрасно жить без него. 3) В PHP легко гибридизирутются ООП и процедурный стили. Это нормально. Не извращение, не говнокод. Даже ваша операционная система, например, полностью процедурная на низком уровне. Иначе быть не может. А на высоком уровне уже объекты. 4) Боитесь гибридного подхода - юзайте статический класс для БД. У меня, к примеру, в движке 100% процедурное ядро. Просто потому что нет смысла его делать объектным. Почему не статик? Потому что оно не монолитное и состоит из независимых фрагментов, подгружаемых в lazy-режиме. Для БД тоже отдельный фрагмент, разумеется. Все функции, которые нужно отдать наружу, агрегируются через статический API-класс в виде API::псевдонимов. При этом все внешние модули и компоненты в обязательном порядке являются объектами. При этом все работает четко, быстро и очень аккуратно расходует оперативу на запрос. Я уже не первый раз форсю тут одну из заповедей разраба - не делай что-то только ради того, чтобы оно было. ООП ради ООП, код ради кода. Если ООП пришло в PHP сравнительно недавно, это не значит что оно лучше процедурного подхода. А процедурный подход не хуже ООП. Молоток не лучше гаечного ключа. Гаечный ключ не лучше дрели. Но дырку в стене лучше делать именно дрелью, а не гаечным ключом. У каждого инструмента свое назначение.