Эта функция дает мне бесконечный цикл
function getCats($parent,$level){ // retrieve all children of $parent $result = ""; $query = "SELECT title,parent_id from t_cats where parent_id = '$parent'"; if($rs = C_DB::fetchRecordset($query)){ while($row = C_DB::fetchRow($rs)){ $result .= str_repeat($parent,$level).$row['title']."\n"; getCats($row['parent_id'],$level+1); } } return $result; }
вот моя таблица db
CREATE TABLE `db`.`t_cats` ( `ID` int(10) unsigned NOT NULL auto_increment, `datasource_id` int(10) unsigned default '0', `version` char(10) character set latin1 default 'edit', `status` char(10) character set latin1 default 'new', `modified_date` datetime default NULL, `modified_by` int(10) unsigned default '0', `title` char(255) character set latin1 default NULL, `parent_id` int(11) default NULL, PRIMARY KEY (`ID`), KEY `idx_datasource_id` (`datasource_id`) ) ENGINE=MyISAM AUTO_INCREMENT=50 DEFAULT CHARSET=utf8;
Я просто хочу, чтобы мой список категорий был рекурсивным.
Но что я делаю неправильно?
РЕДАКТИРОВАТЬ:
function getCats($parent,$level){ // retrieve all children of $parent $result =""; $query = "SELECT title,parent_id from t_cats where parent_id = '$parent'"; if($rs = C_DB::fetchRecordset($query)){ while($row = C_DB::fetchRow($rs)){ $result.= str_repeat($parent,$level).$row['title']."\n"; getCats($row['id'],$level + 1 ); } } return $result; }
Эта строка выглядит неправильно:
getCats($row['parent_id'],$level+1);
Вы должны называть его текущим идентификатором ребенка – в тот момент, когда вы вызываете его с тем же идентификатором снова и снова. Что-то вроде этого (вам нужно выбрать идентификатор из таблицы):
getCats($row['id'], $level + 1);
Изменить: вам нужно обновить свой запрос, чтобы выбрать id
:
$query = "SELECT id, title, parent_id from t_cats where parent_id = '$parent' AND id != parent_id";
Я также добавил немного, чтобы остановить его попадание в цикл, если элемент является его собственным родителем.
Я нашел эту статью SitePoint « Хранение иерархических данных в базе данных » очень полезной. Это все примеры PHP, и это улучшит производительность того, что вы пытаетесь сделать резко .
Может быть, один из элементов в db сам по себе является родителем?
Я не знаю C_DB, но я бы сказал, что $ rs, возвращаемый fetchrecordset, является ссылкой, что означает, что каждый вызов getCats использует те же $ rs. Именно то, что он будет делать, непредсказуемо, в зависимости от того, как реализована функция fetchRow.
Если вы хотите это сделать (и рекурсивное закрытие – это боль в SQL, я знаю), вы должны открыть новое соединение внутри getCats. и использовать отдельный доступ для каждого доступа.
правильный ответ, предоставленный greg …
2 примечания стороны:
в случае бесконечных циклов, глубина рекурсии трека (здесь вы можете удобно использовать $level
) или общий счет вызова (если вы ленивы, так как это oneliner, обращающийся к глобальному счетчику) и прекратить рекурсию с исключением, когда она достигает максимальное значение (в общем, 10 уже достаточно, чтобы увидеть проблему, но, конечно, это может меняться) … а затем получить отладочный вывод … например, $query
или что-то вроде "calling getCats($parent,$level)"
… показал бы вам проблему в мгновение ока в этом случае … 🙂
вы должны свести к минимуму количество запросов … обход дерева таким образом довольно неэффективен … особенно, если база данных находится на другом компьютере …
Greetz
back2dos
Erm не должно быть:
$query = "SELECT title,parent_id from t_cats where id = '$parent'";
И не:
$query = "SELECT title,parent_id from t_cats where parent_id = '$parent'";