За последние 24 часа нас посетили 20298 программистов и 1726 роботов. Сейчас ищут 2179 программистов ...

Магия рекурсии или я устал.

Тема в разделе "PHP для профи", создана пользователем askanim, 25 ноя 2017.

  1. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Короче вот метод который дёргает сам себя.
    PHP:
    1. public function getParentCategory($categoryID) {
    2.         if (empty($this->bookCategoryName)) return false;
    3.         // Сделаем запрос к бд для получения категорий
    4.         $bookCategory = new Book($this->bookCategoryName);
    5.         $bookCategory->where(['id' => $categoryID]);
    6.         $category = $bookCategory->getFetch(); // Получаю данные о категории
    7.         if ($this->test == 'unit') {
    8.                 echo '<pre>';
    9.                 print_r($category);      
    10.                 echo '</pre>';
    11.         }
    12.      
    13.         if (!empty($category)) {
    14.             //$this->parent_category[$category['id']] = $category; // ложу данные
    15.             array_unshift($this->parent_category, $category); // Ложу данные в начало массива
    16.             $this->getParentCategory($category['parent']);
    17.         }
    18.     }
    Короче вот что я вижу когда вывожу на экран при каждом вызове рекурсии
    Код (Text):
    1. <pre>Array
    2. (
    3.     [id] => 76
    4.     [parent] => 71
    5.     [name_category] => 2001
    6.     [uri_category] => 2001
    7.     [link] => ford_transit##korzina_scepleniya##sceplenie##ford_transit##korzina_scepleniya##sceplenie##2001
    8. )
    9. </pre><pre>Array
    10. (
    11.     [id] => 71
    12.     [parent] => 69
    13.     [name_category] => ford transit
    14.     [uri_category] => ford_transit
    15.     [link] => sceplenie##korzina_scepleniya##ford_focus_3##ford_transit
    16. )
    17. </pre><pre>Array
    18. (
    19.     [id] => 69
    20.     [parent] => 68
    21.     [name_category] => корзина сцепления
    22.     [uri_category] => korzina_scepleniya
    23.     [link] => sceplenie##korzina_scepleniya
    24. )
    25. </pre><pre>Array
    26. (
    27.     [id] => 68
    28.     [parent] => 0
    29.     [name_category] => сцепление
    30.     [uri_category] => sceplenie
    31.     [link] => sceplenie
    32. )
    33. </pre><pre></pre>
    А вот что я вижу когда уже собрал массив покажу два варианта один с помощью array_unshift
    Код (Text):
    1. <pre>Array
    2. (
    3.     [0] => Array
    4.         (
    5.             [id] => 68
    6.             [parent] => 0
    7.             [name_category] => сцепление
    8.             [uri_category] => sceplenie
    9.             [link] => sceplenie
    10.         )
    11.  
    12.     [1] => Array
    13.         (
    14.             [id] => 69
    15.             [parent] => 68
    16.             [name_category] => корзина сцепления
    17.             [uri_category] => korzina_scepleniya
    18.             [link] => sceplenie##korzina_scepleniya
    19.         )
    20.  
    21.     [2] => Array
    22.         (
    23.             [id] => 71
    24.             [parent] => 69
    25.             [name_category] => ford transit
    26.             [uri_category] => ford_transit
    27.             [link] => sceplenie##korzina_scepleniya##ford_focus_3##ford_transit
    28.         )
    29.  
    30.     [3] => Array
    31.         (
    32.             [id] => 76
    33.             [parent] => 71
    34.             [name_category] => 2001
    35.             [uri_category] => 2001
    36.             [link] => ford_transit##korzina_scepleniya##sceplenie##ford_transit##korzina_scepleniya##sceplenie##2001
    37.         )
    38.  
    39.     [4] => Array
    40.         (
    41.             [id] => 68
    42.             [parent] => 0
    43.             [name_category] => сцепление
    44.             [uri_category] => sceplenie
    45.             [link] => sceplenie
    46.         )
    47.  
    48.     [5] => Array
    49.         (
    50.             [id] => 69
    51.             [parent] => 68
    52.             [name_category] => корзина сцепления
    53.             [uri_category] => korzina_scepleniya
    54.             [link] => sceplenie##korzina_scepleniya
    55.         )
    56.  
    57.     [6] => Array
    58.         (
    59.             [id] => 71
    60.             [parent] => 69
    61.             [name_category] => ford transit
    62.             [uri_category] => ford_transit
    63.             [link] => sceplenie##korzina_scepleniya##ford_focus_3##ford_transit
    64.         )
    65.  
    66.     [7] => Array
    67.         (
    68.             [id] => 68
    69.             [parent] => 0
    70.             [name_category] => сцепление
    71.             [uri_category] => sceplenie
    72.             [link] => sceplenie
    73.         )
    74.  
    75.     [8] => Array
    76.         (
    77.             [id] => 69
    78.             [parent] => 68
    79.             [name_category] => корзина сцепления
    80.             [uri_category] => korzina_scepleniya
    81.             [link] => sceplenie##korzina_scepleniya
    82.         )
    83.  
    84.     [9] => Array
    85.         (
    86.             [id] => 71
    87.             [parent] => 69
    88.             [name_category] => ford transit
    89.             [uri_category] => ford_transit
    90.             [link] => sceplenie##korzina_scepleniya##ford_focus_3##ford_transit
    91.         )
    92.  
    93. )
    94. </pre>
    Может я уже конечно сплю но что за магия почему их 9 ? Почему они дублируются чё не так?
    Теперь второй вариант это где я присваиваю сам в массив ($this->parent_category[$category['id']] = $category;) и в результате вижу:

    Код (Text):
    1. <pre>Array
    2. (
    3.     [71] => Array
    4.         (
    5.             [id] => 71
    6.             [parent] => 69
    7.             [name_category] => ford transit
    8.             [uri_category] => ford_transit
    9.             [link] => sceplenie##korzina_scepleniya##ford_focus_3##ford_transit
    10.         )
    11.  
    12.     [69] => Array
    13.         (
    14.             [id] => 69
    15.             [parent] => 68
    16.             [name_category] => корзина сцепления
    17.             [uri_category] => korzina_scepleniya
    18.             [link] => sceplenie##korzina_scepleniya
    19.         )
    20.  
    21.     [68] => Array
    22.         (
    23.             [id] => 68
    24.             [parent] => 0
    25.             [name_category] => сцепление
    26.             [uri_category] => sceplenie
    27.             [link] => sceplenie
    28.         )
    29.  
    30.     [76] => Array
    31.         (
    32.             [id] => 76
    33.             [parent] => 71
    34.             [name_category] => 2001
    35.             [uri_category] => 2001
    36.             [link] => sceplenie##korzina_scepleniya##ford_transit##2001
    37.         )
    38.  
    39. )
    Вот что это за нахер, что за магия турецко китайских индусов.... Как оно может идти сначала вот так:
    Код (Text):
    1. (
    2.     [id] => 76
    3.     [parent] => 71
    4.     [name_category] => 2001
    5.     [uri_category] => 2001
    6.     [link] => ford_transit##korzina_scepleniya##sceplenie##ford_transit##korzina_scepleniya##sceplenie##2001
    7. )
    Это напервом месте а потом вдруг стать на последнем што это такое ваще? Где логика
    --- Добавлено ---
    Так ладно это я уже уснул, нашёл ошибку, снемите тему плиз. Не там искал просто её.
     
  2. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Но всё таки магия есть, смотреть два часа на рекурсию и думать о ней как чё там внутри почему не так, это как смотреть в картинку которая крутится, и тебя потихоньку начинает всасывать внутрь.
     
  3. mkramer

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

    С нами с:
    20 июн 2012
    Сообщения:
    8.584
    Симпатии:
    1.762
    @askanim, нам препод на первом курсе говорил, что мозги у программистов бывают рекурсивные и итеративные :) У кого рекурсивные, тот легко хватает рекурсию.
     
  4. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    когда хочешь спать - всегда дешевле лечь спать :)
     
    Taktreba и Fell-x27 нравится это.
  5. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    я так понимаю, это какое-то древовидное меню, которое ты формируешь (судя по названию и по добавлению элементов в начало массива) от конечной категории к коренной?
     
  6. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @TeslaFeo Это в моём движке формирую ссылки для категорий. Исходя от имени каждого родителя, и не посредственно самой категории, это позволяет использовать чпу, и из чпу потом выбрать категорию, любого уровня вложенности, и при этом вероятность ошибки при одинаковых именах категорий крайне мала если только кто-то специально не начнёт кучи одинаковых категорий вводить, но тут фишка выдаст первую строку из таблицы :)
    --- Добавлено ---
    да именно от конечной категории к коренной.
    --- Добавлено ---
    при создании категории в движке формируется под неё уникальная ссылка с именем категории, что потом позволит мне дёргать прямо строкой из гета вот таким образом :
    гет строка:
    /sceplenie/ford-focus-3
    А вот контроллер:
    PHP:
    1.  $url = $request->getAttribute('params');
    2.         $params = explode('/', $url);
    3.         $res = [];
    4.         $res['uri'] = $url;
    5.         $res['paramsURI'] = $params;
    6.         $page = \Application\Model\Site\Pages::getPageByName('catalog');
    7.         if(!empty($page)) {
    8.             $res['modules'] = $this->getModules($page['id']);
    9.             $res['page_name'] = $page['name'];
    10.         }
    11.         $bookFacade = new FacadeBook(2);
    12.         $check = $bookFacade->checkBook();
    13.         if ($check === false) {
    14.             $res['type'] = 'error';
    15.             $res['text'] = 'ВСЁ ПРОПАЛО! Обратитесь в службу поддержки.';
    16.             $this->view->render($response, 'pages/catalog.php', $res);
    17.             return $request;
    18.         }
    19.         $bookName = $bookFacade->getNameBook();
    20.         if (empty($bookName)) {
    21.             $res['type'] = 'error';
    22.             $res['text'] = 'ВСЁ ПРОПАЛО! Обратитесь в службу поддержки.';
    23.             $this->view->render($response, 'pages/catalog.php', $res);
    24.             return $request;
    25.         }
    26.         $linkCategory = implode('##', $params);
    27.         $category = $bookFacade->getCategoryByLinkPath($linkCategory);
    28.         if (empty($category)) {
    29.             $res['type'] = 'error';
    30.             $res['text'] = 'Категории не существует!';
    31.             $this->view->render($response, 'pages/catalog.php', $res);
    32.             return $request;
    33.         }
    34.         $res['category'] = $category;
    35.         $categories = $bookFacade->getCategoryByParentID($category['id']);
    36.         if (empty($categories)) {
    37.             $res['products'] = $bookFacade->getElementsByCategoryID($category['id']);
    38.         }
    39.         else {
    40.             $res['categories'] = $categories;
    41.         }
    42.         $this->view->render($response, 'pages/catalog.php', $res);
    43.         return $request;
    --- Добавлено ---
    правда где продукты надо ещё пагинацию подрубить.
    --- Добавлено ---
    надо домодернезировать метод получения элементов внести туда лимит и возможную сортировку.
    --- Добавлено ---
    а вообще у меня есть facade для пагинации
    PHP:
    1. <?php
    2. /**
    3. * Created by PhpStorm.
    4. * User: strim
    5. * Date: 05.10.2017
    6. * Time: 14:34
    7. */
    8.  
    9. namespace Application\Modules\Facade;
    10.  
    11. use Application\System\Facade\Modules\GetDataModule;
    12. use Application\System\Facade\Pagination;
    13. class GetData
    14. {
    15.     /*
    16.      * Функция получения данных
    17.      * С пагинацией
    18.      *
    19.      * */
    20.     public function get($table_name, $id_page, $max_page, $order)
    21.     {
    22.         $countRows = GetDataModule::countQuery($table_name);
    23.         $max_page = $max_page*1;
    24.         $id_page = $id_page*1;
    25.         $paginate = new Pagination($countRows['count_rows']*1, $id_page, 2,2, $max_page);
    26.         $err = $paginate->getError();
    27.         if (!empty($err)) {
    28.             $message = '';foreach ($err As $key => $value){$message .= $value;}throw new \Exception($message);
    29.         }
    30.         $newPageArray = $paginate->getPagination();
    31.         $first_page = $paginate->getFirst();
    32.         $last_page = $paginate->getLast();
    33.         $min = $max_page*$id_page;
    34.         $min = $min-$max_page;
    35.         $dataTable = GetDataModule::query($table_name, '', $order, $min, $max_page);
    36.         return [
    37.             'data' => $dataTable,
    38.             'navigation' => [
    39.                 'page_array' => $newPageArray,
    40.                 'first_page' => $first_page,
    41.                 'last_page' => $last_page,
    42.                 'current_page' => $id_page
    43.             ]
    44.         ];
    45.     }
    46. }
    Надо его просто тоже чутка модернезировать с условием если выборка идёт по какому то определённому полю.
     
  7. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    а почему не от коренной к конечной? Так же проще на много.
     
  8. igordata

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

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    1. при проходе по списку рекурсия не нужна
    2. твоя рекурсия ничего не возвращает
    конец
     
  9. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    какой список? Это обход родителей и детей по категории. У меня безконечная вложенность в категориях. Чтобы обойти от ребёнка к родителю. Ток рекурсивно можно обойти все элементы как подругому обойти ещё если расскажешь буду знать.
    Потому что когда ты создаёшь в админке категорию ты имеешь не родителя на руках а имеешь лишь ребёнка.
    --- Добавлено ---
    рекурсия не обязательно должна что то возвращать
     
  10. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    Ну да. Создаешь и указываешь родительскую категорию.
    Коренным указываешь parent_id = 0
    Выбираешь все категории с нулём (коренные), попутно выбираешь категории, у которых parent_id == id текущей категории и выстраиваешь их в подкатегорию и т д

    А то, что ты задумал - я даже не могу алгоритм такой построить сходу)
    Там всё сложнее.
     
  11. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    у меня не чего указывать не надо ты конкретно открываешь категорию и говоришь здесь создать ещё категорию.
    У меня не просто родитель ребёнок. У меня движок умеющий делать каталоги с категориями. В любом из каталогов может быть бесконечная вложенность категории, и когда пользователь захочет создать категорию ему нужно идти все id категории собирать чтобы выстроить для программы алгоритм ? :D забавно, программа долнжна знать сама откуда чего и куда, и я это сделал она сама всё внутри знает.
    --- Добавлено ---
    а если там 10 уровень вложенности ?:D
    --- Добавлено ---
    я не чего не задумал я уже всё реализовал, в движке категории создаются, на сайте пути чпу, всё окей
    --- Добавлено ---
    потом дам побаловаться
    движком.
    --- Добавлено ---
    когда допишу модуль в админке для соединения справочников(каталогов), с сайтами в разрез модульной системы которая там изначально стояла у меня. Пока что ручками, создаю контроллер, для вывода каталога. я его уже выше приводил. Но в скоре это ручками писать не надо будет:D скоро я сделаю модуль для вывода каталога.
     
  12. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    Я не пытаюсь обесценить твои достижения. Просто мне не понятен твой подход.
    да хоть 50. Если не дрючить БД запросами, то для php это "ТЬФУ и растереть"
    --- Добавлено ---
    и строить ничего каждый раз не надо.
    Если хочешь создать подкатегорию для категории - просто указываешь первой parent_id второй.
     
  13. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @TeslaFeo т.есть ты предлагаешь мне выбрать все категории с парент id 0 из базы где 250 скажем категорий обойти каждую в цикле и обстроить дерево внутренних элементов при чём там надо будет отсеивать от дочернего элемента
    --- Добавлено ---
    @TeslaFeo ты не понимаешь чувак)
    --- Добавлено ---
    @TeslaFeo ты предлагаешь мне много раз в цикле обойти заместо одного запроса к бд. Со страницы сайта. Это специальная рекурсия для построения чпу ссылки которую я прямо потом из гета долбану в таблицу получу id категории что тут не понятного ? А для этого мне пришлось в админке при создании категории генерировать уникальный урл, соответствующий чпу!
    --- Добавлено ---
    я же писал создание чпу! http://ford-domodedovo.ru/ вот загляни, пока тока успел каталог реализовать, потыкай в нём посмотри на url всё поймёшь
     
  14. Abyss

    Abyss Старожил

    С нами с:
    12 дек 2015
    Сообщения:
    1.298
    Симпатии:
    218
    Адрес:
    Default city
    Нужно больше запросов, база данных должна умереть !
     
    Fell-x27 нравится это.
  15. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    если тебе не нужно от корня, то и не нужно parent_id 0
     
  16. Maputo

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

    С нами с:
    30 июл 2015
    Сообщения:
    1.136
    Симпатии:
    173
    Возможно Вам поможет паттерн Composite
     
  17. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    у друпала около 200 запросов при выводе каталога, чёт он не мрёт.... А тут ну максимум 10-15 будет.
    --- Добавлено ---
    И это в админки где скорее всего более сотни не будет человек работать. И то на определённом месте и при создании новой или изменении категории и то при изменении её родителя или имени
     
  18. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    значит друпал гавно.
    походу нормальных CMS вообще не существует.
    Качество кода прямопропорционально компетентности ЦА.
     
  19. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    @TeslaFeo когда ты делаешь большой проект, у тебя в опреоре будет множество запросов к бд, и от того что где то происходит рекурсионный запрос по аяксу страшного не чего не случится. Серв не упадёт и мир не рухнет от 15 простых запросов к бд, которые произойдут за 0.1 мс
    --- Добавлено ---
    и даже меньше
    --- Добавлено ---
    говорю факты имею практический опыт. Не верите сами попробуйте и подумайте.
     
  20. TeslaFeo

    TeslaFeo Старожил

    С нами с:
    9 мар 2016
    Сообщения:
    2.984
    Симпатии:
    759
    @askanim я про 200 запросов и CMS говорил.
    В твоём опыте не сомневаюсь)
    А вот в том, что ты принимаешь всё на свой счет - хорошего мало.
    Больно так жить.
     
  21. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    Я тоже думаю что друпал какашка, там 50 запросов минимум на страницу приходится!
    --- Добавлено ---
    Но он хотябы в разрабокте понятен! А вот битрикс вообще лажа я вообще не могу понять как структура таблиц у него устроена, там ваще жопа на обычный инет магазин у битрикса просто около 300 таблиц в бд ет чё за ересь какая то, там ещё и по всему видимому какой то эмулятор на линуксе стоит bitrix VM что это за дичь я хз.
     
  22. voral

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

    С нами с:
    30 ноя 2017
    Сообщения:
    646
    Симпатии:
    104
    Зачем такая сложная рекурсия?
    Зачем плодить запросы к БД. Есть же Nested Sets (который, кстати, используется и в Битрикс для хранения разделов). Используя его можно одним запросом (или точнее двумя) получить сразу хоть всех родителей, хоть всех потомков, хоть соседей.....

    У Битрикс такое число запросов обусловлено большой гибкостью. Самый центровой модуль пока не перписали на новое ядро - очень много зависимостей. При этом многозависит от внедряющего - мне встречались сайтына которых поленившийся прочитать доку программист доводил до того, что на каждом хите выполнялось до 3тысяч запросов включая тяжелые. Приводишь все в порядок и количество запросов снижается до десятка (за исключением случая когда кеш протухает, но и вэтом случае "тысячи" - это криворучие внедряющего)

    bitrix VM это ни разу не эмулятор.... Естьтакое понятие как битрикс окружение. Просто linux скрипт (пакет даже) который запускаешь и он настраивает голую систему для оптимальной работы битрикс. В поседующем можно при помощи скрипта из этого пакета админить некоторые параметры. Плюсом пакет подготавливает все, чтоб можно было управлять масштабированием и кластеризацией из админки... Плюс идут готовые слепки для виртуальных машин, где уже стоит CentOS и окружение битрикс......
     
  23. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    я знаю как сделать без рекурсии (И тема старая, уже давно переделано), мне надо было сделать быстро я сделал не ломая голову как мне сделать, Nested Sets не является лучшим решением как минимум. И в данном случае там не было вариантов сделать по другому потому что категории уже были созданы и они не копили предыдущий результат и каждая ниже рекурсия только знала кто её отец, а не всех потомков, это писалось для того чтобы как раз сделать так чтобы были уже накопленные знания о всех отцах, на существуещем каталоге.
     
  24. Fell-x27

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

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.770
    Адрес:
    :сердА
    Установи отладчик.
    --- Добавлено ---
    Это плохо. Это структура для хранения однонаправленных связных списков в БД, а не деревьев. Горя ты с этим хлебнешь еще неоднократно. Nested Sets, Materialized Path и тд не просто так придумали.
     
    askanim нравится это.
  25. askanim

    askanim Старожил

    С нами с:
    7 апр 2016
    Сообщения:
    2.201
    Симпатии:
    166
    Адрес:
    GABRIEL
    я согалсен, но я переделал. Я теперь при создании категории, записываю путь до отца.
    --- Добавлено ---
    описался, "Они не копили предыдущий результат и каждый след ребёнок знал только прямого над ним отца"