Рекурсия — определение, описание, изображение какого-либо объекта или процесса внутри самого этого объекта или процесса, то есть ситуация, когда объект является частью самого себя. Другими словами, рекурсия - это вызов функции внутри самой себя.
Простой пример рекурсии в 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);
Основы хранения в БД древовидных структур можно почитать здесь.
Комментарии (0)
Пока еще не было комментариев ✍️