Как можно реализовать рекурсивную функцию, которая на основе массива (с возможной неограниченной вложенностью) формирует список, используя только один аргумент и выводя тег ul только один раз в начале и в конце? Код должен работать без использования функций вроде str_replace и других подобных. Вот пример массива: ```php $arr = [ 'id' => 1, 'name' => 'item1', 'items' => [ ['id' => 2, 'name' => 'item2', 'items' => [], ], ['id' => 3, 'name' => 'item3', 'items' => [], ], [ 'id' => 4, 'name' => 'item4', 'items' => [ ['id' => 5, 'name' => 'item5', 'items' => [], ], ['id' => 6, 'name' => 'item6', 'items' => [], ] ] ] ] ]; ``` Какой код у меня сейчас: ```php function list_form(array $array) { $str = ''; foreach ($array as $key => $val) { if (is_array($val)) { $str .= "<li>$key =></li>"; if (!empty($val)) { $str .= list_form($val); } } else { $str .= "<li>$key => $val</li>"; } } return "<ul>" . str_replace(["<ul>", "</ul>"], '', $str) . "</ul>"; } echo list_form($arr); ``` Как можно улучшить этот код для достижения поставленной задачи?
Чтобы реализовать рекурсивную функцию, которая формирует список только с одним открывающим и одним закрывающим тегом `<ul>`, можно изменить вашу текущую функцию следующим образом. Основная идея заключается в том, чтобы: 1. Добавить открывающий тег `<ul>` в самом начале функции. 2. Убедиться, что закрывающий тег `</ul>` добавляется только в конце, вне зависимости от количества вложенных массивов. Вот пример реализации такой функции: ```php function list_form(array $array) { $str = '<ul>'; // Начинаем с открывающего тега <ul> foreach ($array as $item) { if (is_array($item)) { $str .= '<li>' . htmlspecialchars($item['name']) . '</li>'; // Добавляем элемент списка // Если у элемента есть вложенные элементы if (!empty($item['items'])) { // Рекурсивно добавляем вложенные элементы $str .= list_form($item['items']); } } else { $str .= '<li>' . htmlspecialchars($item) . '</li>'; // Обрабатываем не массивы, если такие имеются } } $str .= '</ul>'; // Добавляем закрывающий тег </ul> return $str; } // Пример массива $arr = [ [ 'id' => 1, 'name' => 'item1', 'items' => [ ['id' => 2, 'name' => 'item2', 'items' => []], ['id' => 3, 'name' => 'item3', 'items' => []], [ 'id' => 4, 'name' => 'item4', 'items' => [ ['id' => 5, 'name' => 'item5', 'items' => []], ['id' => 6, 'name' => 'item6', 'items' => []] ] ] ] ] ]; echo list_form($arr); ``` ### Что было изменено: 1. Убран цикл по ключам и значениям, вместо этого я стал обращаться непосредственно к элементам массива. 2. Начальный тег `<ul>` добавляется сразу в начале функции, а закрывающий тег `</ul>` добавляется в конце. 3. Используется `htmlspecialchars()` для предотвращения XSS при выводе данных. Запустив приведенный код с вашим массивом, вы получите корректный вывод списка с учетом вложенности, формируя HTML-разметку в соответствии с вашими требованиями.
непонятно должна ли быть функция рекурсивная, сделал итеративную версию с состоянием:
<?php $arr = [ 'id' => 1, 'name' => 'item1', 'items' => [ [ 'id' => 2, 'name' => 'item2', 'items' => [], ], [ 'id' => 3, 'name' => 'item3', 'items' => [], ], [ 'id' => 4, 'name' => 'item4', 'items' => [ [ 'id' => 5, 'name' => 'item5', 'items' => [], ], [ 'id' => 6, 'name' => 'item6', 'items' => [], ], ], ], ], ]; function list_form(array $input) { $result = [ '<ul>', ]; $state = [ [ 'array' => $input, 'keys' => array_keys($input), 'idx' => 0, ], ]; for (; count($state) > 1 || $state[0]['idx'] < count($state[0]['keys']); $state[0]['idx'] += 1) { if (count($state) > 1 && $state[0]['idx'] === count($state[0]['keys'])) { array_shift($state); continue; } $key = $state[0]['keys'][$state[0]['idx']]; $value = $state[0]['array'][$key]; if (!is_array($value)) { $result[] = "<li>$key => $value</li>"; } else { $result[] = "<li>$key => []</li>"; if (!count($value)) continue; array_unshift($state, [ 'array' => $value, 'keys' => array_keys($value), 'idx' => -1, ]); } } $result[] = '</ul>'; return implode("\n", $result); } echo list_form($arr);