Примеры использования рекурсивной функции в PHP
Рекурсия — определение, описание, изображение какого-либо объекта или процесса внутри самого этого объекта или процесса, то есть ситуация, когда объект является частью самого себя. Другими словами, рекурсия - это вызов функции внутри самой себя.
Простой пример рекурсии в PHP
Ниже показан примитивный пример использования рекурсии. По сути, ничего полезного данный код не делает. Более того, такой скрипт (бесконечный) переполнит стэк и аварийно завершит свою работу. Мы получим ошибку: Fatal error: Uncaught Error: Maximum function nesting level of '256' reached, aborting!
.
function recursion() { recursion(); } recursion();
Факториал
Чтобы избавится от бесполезного и бесконечного вызова функции, необходимо прописать условие при котором эта функция вызывала бы сама себя, делая при этом что-то полезное и нужное. В классическом исполнение хорошо подходит пример функции вычисляющей факториал числа.
Факториал - произведение всех целых чисел, меньших или равных данному числу.
function factorial($n) { if ($n <= 1) return 1; return $n * factorial($n - 1); // здесь происходит повторный вызов функции } echo factorial(5); // 120
Факториал числа так же можно вычислить, применив цикл, полностью заменяющий рекурсию:
function factorial($n) { $result = 1; for ($i = 1; $i <= $n; $i++) { $result *= $i; } return $result; } echo factorial(5); // 120
Пример функции для защиты от XSS
Практически все данные (за редким исключением) из форм необходимо, во избежания XSS, пропускать через функцию htmlspecialchars()
. Наша задача написать такую функцию, которая будет принимать массив (включая вложенные массивы) всех входящих данных и "прогонять" эти данные через встроенную функцию php htmlspecialchars()
. И как раз здесь мы будем использовать рекурсию.
<?php function xss($data) { if (is_array($data)) { // Если это массив $result = array(); // Создаём новый массив foreach ($data as $key => $value) { // Перебираем исходный массив $result[$key] = xss($value); // Рекурсивно вызываем функцию xss } return $result; // Возвращаемый "защищённый" массив } return htmlspecialchars($data, ENT_QUOTES); // Если это не массив, то вызываем htmlspecialchars() } // Предположим, что в строке запроса у нас такая строка: // /?name=John&age=<>45 $data = xss($_REQUEST); // Вызываем функцию, передав туда в качестве аргумента весь REQUEST // Распечатаем результат var_dump($data);
Класс дерева категорий
В данном примере выведем дерево категорий, используя рекурсивный метод, написанный в ООП стиле.
CREATE TABLE IF NOT EXISTS category ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(100) NOT NULL, `parent_id` VARCHAR(40) NOT NULL, PRIMARY KEY ( id ) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO category (`id`, `name`, `parent_id`) VALUES (1, 'Компьютеры и периферия', 0), (2, 'Комплектующие для ПК', 0), (3, 'Смартфоны и смарт-часы', 0), (4, 'Телевизоры и медиа', 0), (5, 'Игры и приставки', 0), (6, 'Аудиотехника', 0), (7, 'Фото-видеоаппаратура', 0), (8, 'Офисная техника и мебель', 0), (9, 'Компьютерные системы', 1), (10, 'Периферия', 1), (11, 'Программное обеспечение и аксессуары', 1), (12, 'Системные блоки', 9), (13, 'Моноблоки', 9), (14, 'Неттопы и компьютеры-флешки', 9), (15, 'Платформы', 9), (16, 'Игровые компьютеры', 12), (17, 'Компьютеры для офиса', 12), (18, 'Компьютеры для бизнеса', 12), (19, 'Сенсорные моноблоки', 13), (20, 'Моноблоки с IPS экраном', 13), (21, 'Моноблоки с VA экраном', 13), (22, 'Моноблоки с TN экраном', 13), (23, 'Основные комплектующие', 2), (24, 'Хранение данных и охлаждение', 2);
Класс Category
:
<?php require 'DB.php'; class Category { /** * @return array * Получаем все категории */ public function getData() { $db = new DB(); return $db::getRows("SELECT * FROM `category`"); } /** * @param $data * @return mixed * Строим дерево */ public function createTree($data) { $parents = []; foreach ($data as $key => $item): $parents[$item->parent_id][$item->id] = $item; endforeach; $treeElem = $parents[0]; $this->generateElemTree($treeElem, $parents); return $treeElem; } /** * @param $treeElem * @param $parents * Генерируем элементы дерева с учётом удобного вывода потомков */ private function generateElemTree(&$treeElem, $parents) { foreach ($treeElem as $key => $item): if (!isset($item->children)): $treeElem[$key]->children = []; endif; if (array_key_exists($key, $parents)): $treeElem[$key]->children = $parents[$key]; $this->generateElemTree($treeElem[$key]->children, $parents); endif; endforeach; } /** * @param $data * Рендерим вид */ public function renderTemplate($data) { echo "<ul>"; if(is_array($data)): foreach ($data as $item): echo '<li>'; echo "<a href=\"/?=/{$item->id}\">"; echo $item->name; echo "</a>"; if(count($item->children) > 0): $this->renderTemplate($item->children); endif; echo '</li>'; endforeach; endif; echo "</ul>"; } }
Выводим дерево категорий:
require 'Category.php'; $category = new Category(); $data = $category->getData(); $tree = $category->createTree($data); $category->renderTemplate($tree);
Основы хранения в БД древовидных структур можно почитать здесь.