<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 22:59:35 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="QNipi3EuHyFGO9E828CeyjtvuHO2SODLYzpXAGoz326vCWK8g1CyQfB49aTXz269-2aV2b5_Hmne2s1UODQ4AA";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Манипуляции с виртуальной файловой системой | PHP: Деревья</title>
<meta name="description" content="Манипуляции с виртуальной файловой системой / PHP: Деревья: Учимся изменять файловую систему в неизменяемом стиле">
<link rel="canonical" href="https://ru.hexlet.io/courses/php-trees/lessons/manipulations/theory_unit">
<meta name="robots" content="noarchive">
<meta property="og:title" content="Манипуляции с виртуальной файловой системой">
<meta property="og:title" content="PHP: Деревья">
<meta property="og:description" content="Манипуляции с виртуальной файловой системой / PHP: Деревья: Учимся изменять файловую систему в неизменяемом стиле">
<meta property="og:url" content="https://ru.hexlet.io/courses/php-trees/lessons/manipulations/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="18A5CJUm2olYx1E0spzpOu_QeVOL9obB4-FLeK_GE0A4EfI_Z1h36e6Eday-kxlNL9lU-YPBeGNeAdEs_cH0Lg" />
<script src="/vite/assets/inertia-DfXos102.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-cb8xch9l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk5MiwicHVyIjoiYmxvYl9pZCJ9fQ==--e9d0f30948ea766a7e6bc3e3d56c192344d45fb8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programming-cuate%20(1).png"/><link rel="preload" as="image" href="/vite/assets/development-BVihs_d5.png"/><div id="app" data-page="{"component":"web/courses/lessons/theory_unit","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T22:59:34.967Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"addX1cTAtUFcrLxxitXpayN9wVEXxTux9VUHmrD20iqGBpziNr4YIervmOmG2hkc43Ts-x_yxRNItZ3O4vE1RA","topics":[{"id":42091,"title":"Добрый день! В примере про обновление содержимого директории в итоговом дереве директория \"THREE\" становится файлом. Возможно, правильно будет так?\n```\n$children = getChildren($tree);\n$newChildren = array_map(function ($child) {\n $name = getName($child);\n if (isFile($child)) {\n return mkfile(strtolower($name), getMeta($child));\n }\n return mkdir(strtolower($name), getMeta($child));\n}, $children);\n\n$tree2 = mkdir(getName($tree), $newChildren, getMeta($tree));\n```","plain_title":"Добрый день! В примере про обновление содержимого директории в итоговом дереве директория \"THREE\" становится файлом. Возможно, правильно будет так? ``` $children = getChildren($tree); $newChildren = array_map(function ($child) { $name = getName($child); if (isFile($child)) { return mkfile(strtolower($name), getMeta($child)); } return mkdir(strtolower($name), getMeta($child)); }, $children); $tree2 = mkdir(getName($tree), $newChildren, getMeta($tree)); ``` ","creator":{"public_name":"Глеб","id":250879,"is_tutor":false},"comments":[{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":91714,"body":"**Gleb**, приветствую!\n\nСпасибо, что обратили внимание. Поправил.","topic_id":42091}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":41737,"title":"а почему тут\n```\n$newMeta = getMeta($tree);\n$newChildren = array_reverse($children);\n$tree2 = mkdir(getName($tree), $newChildren, $newMeta);\n```\nдля $newMeta отдельная переменная сделана, а для name - нет?","plain_title":"а почему тут $newMeta = getMeta($tree); $newChildren = array_reverse($children); $tree2 = mkdir(getName($tree), $newChildren, $newMeta); для $newMeta отдельная переменная сделана, а для name - нет? ","creator":{"public_name":"Konstantin Zharinov","id":181349,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":91039,"body":"Действительно. :) Курс портировался с JS, там `meta` хранится по ссылке и объявляется её копия. Тут можно не выделять для нее отдельную переменную. Я исправил примеры. Спасибо за внимательность!","topic_id":41737}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":42098,"title":"Что значит сжимает картинки?","plain_title":"Что значит сжимает картинки? ","creator":{"public_name":"Светлана Ильина","id":149206,"is_tutor":false},"comments":[{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":91715,"body":"Приветствую, Светлана!\n\nВ описании к задаче есть пояснение: \"Под сжиманием понимается уменьшение свойства size в метаданных в два раза.\"","topic_id":42098}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":44706,"title":"Прошу старших товарищей и менторов - альтруистов :) оценить мое решение. Оно получилось покомпактнее, чем у сенсея. Видимо я не учел какую то идеологию и обманул сам себя:\nhttps://ru.hexlet.io/code_reviews/285132\n(1 ошибка линтера не в счет :) )","plain_title":"Прошу старших товарищей и менторов - альтруистов :) оценить мое решение. Оно получилось покомпактнее, чем у сенсея. Видимо я не учел какую то идеологию и обманул сам себя: https://ru.hexlet.io/code_reviews/285132 (1 ошибка линтера не в счет :) ) ","creator":{"public_name":"Артем","id":168956,"is_tutor":false},"comments":[{"creator":{"public_name":"Артем","id":168956,"is_tutor":false},"id":96710,"body":"okay :(","topic_id":44706},{"creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"id":96707,"body":"**Артем**, приветствую.\n\nНа самом деле несколько ключевых моментов лежит на поверхности, просто разбирайте решение учителя и думайте почему его решение именно такое.\n\nPS\n\nМенторы не проводят код-ревью (https://help.hexlet.io/article/39-mentors), получить обратную связь по коду можно попробовать в нашем сообществе в Слаке (https://slack-ru.hexlet.io/) в канале #php или перейти на тариф Премиум, где код-ревью является частью проектов (https://help.hexlet.io/article/53-who-is-tutor).","topic_id":44706}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":41790,"title":"Доброго дня! Не лучше ли, пример с удалением файлов написать вот так:\n```\n$children = getChildren($tree);\n$newChildren = array_filter($children, function ($node) {\n return $node['type'] === 'directory';\n});\n$newMeta = getMeta($tree);\n$tree2 = mkdir(getName($tree), $newChildren, $newMeta);\n```\nПросто если оставить в том виде, что и в уроке, то она будет работать только внутри файла trees.php, а это вроде не очень правильно. Или я неправильно понимаю?","plain_title":"Доброго дня! Не лучше ли, пример с удалением файлов написать вот так: $children = getChildren($tree); $newChildren = array_filter($children, function ($node) { return $node['type'] === 'directory'; }); $newMeta = getMeta($tree); $tree2 = mkdir(getName($tree), $newChildren, $newMeta); Просто если оставить в том виде, что и в уроке, то она будет работать только внутри файла trees.php, а это вроде не очень правильно. Или я неправильно понимаю? ","creator":{"public_name":"Никита Ионов","id":239997,"is_tutor":false},"comments":[{"creator":{"public_name":"Никита Ионов","id":239997,"is_tutor":false},"id":91122,"body":"Да, как раз хотел написать, что вроде разобрался. Спасибо!","topic_id":41790},{"creator":{"public_name":"Никита Ионов","id":239997,"is_tutor":false},"id":91180,"body":"Не, у меня работать не будет :) У меня пхп 7.2.24, пока не хотел обновлять конечно... Хекслет уже перешел на 7.4?","topic_id":41790},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":91042,"body":"Приветствую, Никита! \n\nМы по максимуму используем библиотеку @hexlet/immutable-fs-trees. В том числе и в теоретической части. Ваш пример опирается на знание структуры ноды, что не верно, на этом уровне абстракции. Тип `directory` может внутри быть реализован совсем по другому.\n\nВариант из теории работать везде, где подключена библиотека @hexlet/immutable-fs-trees. Я бы порекомендовал вам вернуться к теории урока [Управление зависимостями](https://ru.hexlet.io/courses/php-setup-environment/lessons/composer-dependencies/theory_unit) и [Composer](https://ru.hexlet.io/courses/php-setup-environment/lessons/composer/theory_unit). Это должно прояснить ситуацию с использованием зависимостей и подключением библиотек.","topic_id":41790},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":91174,"body":"Я думаю, тут дело не в подключении, а в том, что в последних версиях PHP не поддерживается передача функции как строки.\n\n $newChildren = array_filter($children, 'isDirectory');\n\nВот тут `isDirectory` передается как строка. Уточните, какая версия PHP у вас установлена?\n\nПопробуйте переписать этот код с использованием стрелочного синтаксиса. Информацию о стрелочных функциях как раз добавили в урок — [Объекты первого класса](https://ru.hexlet.io/courses/php-functions/lessons/first-class-citizen/theory_unit)","topic_id":41790},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":91181,"body":"Да. В данный момент в практиках используется версия PHP 7.4.3.","topic_id":41790},{"creator":{"public_name":"Никита Ионов","id":239997,"is_tutor":false},"id":91116,"body":"Так, не понял. На packagist нет hexlet-components/php-immutable-fs-trees. Я могу установить библиотеку без packagist?","topic_id":41790},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":91176,"body":"Я переписал пример в теории. Можете скопировать его и попробовать запустить локально.","topic_id":41790},{"creator":{"public_name":"Никита Ионов","id":239997,"is_tutor":false},"id":91113,"body":"А, понял. immutable-fs-trees нужно использовать как библиотеку! Я почему-то подумал что это просто рабочий репозиторий. Склонировал себе, создал папку bin с run-файлом и в нем все делаю. Спасибо :)","topic_id":41790},{"creator":{"public_name":"Никита Ионов","id":239997,"is_tutor":false},"id":91172,"body":"Не разобрался...\nУстановил как библиотеку:\n```\n{\n \"name\": \"nekedio/test-rep\",\n \"description\": \"test-rep and linter\",\n \"bin\": [\"./bin/runFile\",\n \"./bin/run2File\",\n \"./bin/run2File\"\n ],\n \"autoload\": {\n \"psr-4\": {\"App\\\\\": \"src/\"},\n \"files\": [\"src/progFile.php\"]\n },\n \"authors\": [\n {\n \"name\": \"Nikita Ionov\",\n \"email\": \"ionov.goo@gmail.com\"\n }\n ],\n \"repositories\": [\n {\n \"type\": \"git\",\n \"url\": \"https://github.com/hexlet-components/php-immutable-fs-trees\"\n }\n ],\n \"require\": {\n \"funct/funct\": \"^1.5\",\n \"hexlet/trees\": \"dev-master\"\n },\n \"scripts\": {\"phpcs\": \"phpcs\"},\n \"require-dev\": {\n \"squizlabs/php_codesniffer\": \"^3.5\"\n }\n\n}\n```\n\nНо при запуске файла:\n```\n<?php\n\nrequire_once __DIR__ . '/../vendor/autoload.php';\n\nuse function PhpTrees\\Trees\\mkdir;\nuse function PhpTrees\\Trees\\mkfile;\nuse function PhpTrees\\Trees\\getChildren;\nuse function PhpTrees\\Trees\\getName;\nuse function PhpTrees\\Trees\\getMeta;\nuse function PhpTrees\\Trees\\isDirectory;\n\n$tree = mkdir('/', [\n mkfile('one'),\n mkfile('two'),\n mkdir('three'),\n]);\n\n$children = getChildren($tree);\n$newChildren = array_filter($children, 'isDirectory');\n$tree2 = mkdir(getName($tree), $newChildren, getMeta($tree));\n\nprint_r($tree2);\n```\nИ все равно возникает ошибка:\n```\nPHP Warning: array_filter() expects parameter 2 to be a valid callback, function 'isDirectory' not found or invalid function name in /home/nekedio/Project/test-rep/bin/runFile on line 21\nPHP Fatal error: Uncaught TypeError: Argument 2 passed to PhpTrees\\Trees\\mkdir() must be of the type array, null given, called in /home/nekedio/Project/test-rep/bin/runFile on line 22 and defined in /home/nekedio/Project/test-rep/vendor/hexlet/trees/src/trees.php:8\nStack trace:\n#0 /home/nekedio/Project/test-rep/bin/runFile(22): PhpTrees\\Trees\\mkdir('/', NULL, Array)\n#1 {main}\n thrown in /home/nekedio/Project/test-rep/vendor/hexlet/trees/src/trees.php on line 8\n```\nНе понимает он что 'isDirectory' это функция из библиотеки.","topic_id":41790},{"creator":{"public_name":"Никита Ионов","id":239997,"is_tutor":false},"id":91229,"body":"Обновил. Все работает. Спасибо!","topic_id":41790},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":91121,"body":"Пакет можно установить напрямую с GitHub. Попробуйте изучить, как подключена библиотека в практике в файле `composer.json`. \n\nА вот здесь подробно рассказывается о том, как это работает — [Loading a package from a VCS repository](https://getcomposer.org/doc/05-repositories.md#vcs)","topic_id":41790}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":41973,"title":"Здравствуйте! В тексте \"isset(getMeta($file)['unknown']);\" требуется поставить запятую:\n\"isset(getMeta($file), ['unknown']);\" Спасибо","plain_title":"Здравствуйте! В тексте \"isset(getMeta($file)['unknown']);\" требуется поставить запятую: \"isset(getMeta($file), ['unknown']);\" Спасибо ","creator":{"public_name":"Александр","id":234930,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр","id":234930,"is_tutor":false},"id":91486,"body":"Теперь понял) Просто раньше всегда был синтаксис \"$arr[...]\", а сейчас \"Функция[...]\". Спасибо","topic_id":41973},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":91422,"body":"Приветствую, Александр!\n\nУточните для чего там требуется запятая. Вначале мы вызываем функцию getMeta($file), вызов которой вернёт ассоциативный массив, и далее из него сразу получаем значение по ключу getMeta($file)['unknown'], после чего мы проверяем полученное значение на существование с помощью isset.","topic_id":41973},{"creator":{"public_name":"Александр","id":234930,"is_tutor":false},"id":91483,"body":"Здравствуйте, Станислав! То есть внутри isset получается ['hidden' => true]['unknown'] ? Просто видать я что-то пропустил - необычно слепилась функция и массив (ключ) - getMeta($file)['unknown'] ?","topic_id":41973},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":91485,"body":"Тут дело не в функции, а в том что она возвращает и это массив. Далее по сути происходит получение значение из массива по ключу. Вот простой пример:\n\n $arr = ['key' => 'value'];\n $arr['key']; // 'value'\n\n function getArray($arr)\n {\n return $arr;\n }\n getArray($arr)['key']; // 'value'\n\nРезультат один и тот же в обеих вариантах ['key' => 'value']['key'].","topic_id":41973}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":59886,"title":"Добрый день [code_review](https://ru.hexlet.io/code_reviews/479604) (первый вариант) во время поиска решения, я распечатал \n`print_r($children)` \n`$children = getChildren($tree)` \nувидел что это массив, и в решении использовал подход как с массивом, т.е. нашел нужный мне элемент (через определенные условия) и изменил значение по ключу. Была мысль воспользоваться `mkfile` как в теории и в решении учителя.\nВопрос: можно ли в контексте данного курса (урока) пользоваться подходом как массив (изменив нужное мне значение) или надо пользоваться именно mkfile (так как мы должны создавать новый файл и возвращать его)? \nЭтот вопрос возник у меня из-за того что мы и в том решении и в том решении, не трогаем исходные данные, мы берем из него то, что нужно, меняем и создаем в конце новое дерево, на основе этих данных.","plain_title":"Добрый день code_review (https://ru.hexlet.io/code_reviews/479604) (первый вариант) во время поиска решения, я распечатал print_r($children) $children = getChildren($tree) увидел что это массив, и в решении использовал подход как с массивом, т.е. нашел нужный мне элемент (через определенные условия) и изменил значение по ключу. Была мысль воспользоваться mkfile как в теории и в решении учителя. Вопрос: можно ли в контексте данного курса (урока) пользоваться подходом как массив (изменив нужное мне значение) или надо пользоваться именно mkfile (так как мы должны создавать новый файл и возвращать его)? Этот вопрос возник у меня из-за того что мы и в том решении и в том решении, не трогаем исходные данные, мы берем из него то, что нужно, меняем и создаем в конце новое дерево, на основе этих данных. ","creator":{"public_name":"Аслан Аутлев","id":289558,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":126543,"body":"Приветствую! Классно, что вы решили задачу!\n\nСмотрите, мы тут работаем с виртуальной файловой системой. Это наш уровень абстракции, поэтому нужно по максимум использовать функции, которые позволяют нам не думать о внутренней реализации это файловой системы. Например, геттер `getName()` возвращает нам имя файла и мы не задумываемся о том, что внутри он представлен массивом. Теоретически его можно реализовать и по другому (как-то иначе хранить данные). Но при этом `getName()` продолжит работать точно также, просто будет возвращать имя. Резюмируя, если у нас есть какая-то абстракция, то нужно стараться использовать интерфейсные (т.е. те которые позволяют работать с ней) функции этой абстракции.","topic_id":59886}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":58534,"title":"Задание выполнил, ничего сложного, просто надо быть внимательным, потому что массивы большие читать тяжело (если ты не настроил себе красивый вывод подключив html). Но у меня вопрос другого характера.\n\nДля чего нужны вот эти навыки работы с деревьями? Это чтобы повысить уровень работы с функциями высшего порядка? На практике эти знания применимы? А то я не понимаю в каком месте все эти функции по типу mkdir могут помочь. Если это своеобразный подход для прокачки тоже норм. Упражнения в принципе интересные.","plain_title":"Задание выполнил, ничего сложного, просто надо быть внимательным, потому что массивы большие читать тяжело (если ты не настроил себе красивый вывод подключив html). Но у меня вопрос другого характера. Для чего нужны вот эти навыки работы с деревьями? Это чтобы повысить уровень работы с функциями высшего порядка? На практике эти знания применимы? А то я не понимаю в каком месте все эти функции по типу mkdir могут помочь. Если это своеобразный подход для прокачки тоже норм. Задания в принципе интересные, просто интересно узнать ","creator":{"public_name":"Ruslan Polonkoev","id":376342,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":123920,"body":"Процитирую определение из урока \"Введение\": \n\n> Дерево — одна из самых распространённых структур данных в информатике и естественный способ моделирования некоторых предметных областей. \n\nУмение работать с деревьями очень важно для программиста. Пример из реальной жизни. Комментарии на сайтах очень часто имеют древовидную структуру (можно отвечать на какой-то конкретный комментарий, а не только в конец их списка как было на форумах). И вот как раз когда нужно будет написать какую-то обработку для комментов и пригодятся знания деревьев. \n\nВ курсе мы работаем с виртуальной файловой системой. Это нужно чтобы можно было лучше усвоить материал и понять как работает рекурсия. \n\nПросто интересный факт. Вы знали, что исходный код, который вы пишете, тоже имеет [древовидную структуру](https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE)? :)","topic_id":58534}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":42348,"title":"Задание конечно изи, но функция endsWith - это круто =)","plain_title":"Задание конечно изи, но функция endsWith - это круто =) ","creator":{"public_name":"Sergey Matveev","id":237733,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":92256,"body":"`lodash` на PHP — это весело. :)","topic_id":42348},{"creator":{"public_name":"Sergey Matveev","id":237733,"is_tutor":false},"id":92267,"body":"PHP вобще весело, особенно после современного JS, делаю второй проект и дико туплю с namespace, autoload, use и т.п. В js было как-то проще с этим, import/export все просто.","topic_id":42348}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}},{"id":51798,"title":"Здравствуйте, подскажите пожалуйста на что ругается линтер (в данных строчках не вижу ничего такого) https://ru.hexlet.io/code_reviews/369325","plain_title":"Здравствуйте, подскажите пожалуйста на что ругается линтер (в данных строчках не вижу ничего такого) https://ru.hexlet.io/code_reviews/369325 ","creator":{"public_name":"Turgay","id":321161,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":110591,"body":"Приветствую!\n\nПроверил ваше решение, в нём нет ошибок линтера. А вот в файлах с тестами парочка ошибок нашлась. Спасибо, что обратили внимание! Ошибка заключалась в том, что пустые строки содержали пробелы, хотя не должны. Линтер также будет ругаться, если оставлять лишние пробелы в конце строк с кодом, например, после завершающей `;`. Я исправил ошибки в тестах, можете выполнить сброс, чтобы обновить упражнение.\n\n","topic_id":51798}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Манипуляции с виртуальной файловой системой","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":1195,"slug":"php_trees_manipulations_exercise","name":null,"state":"active","kind":"exercise","language":"php","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"## src/tree.php\n\nРеализуйте функцию `compressImages()`, которая принимает на вход директорию, находит внутри нее картинки и \"сжимает\" их. Под сжиманием понимается уменьшение свойства `size` в метаданных в два раза. Функция должна вернуть обновленную директорию со сжатыми картинками и всеми остальными данными, которые были внутри этой директории.\n\nКартинками считаются все файлы заканчивающиеся на *.jpg*.\n\n### Примеры\n\n```php\n<?php\n\nuse function Php\\Immutable\\Fs\\Trees\\trees\\mkdir;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\mkfile;\nuse function App\\tree\\compressImages;\n\n$tree = mkdir(\n 'my documents', [\n mkfile('avatar.jpg', ['size' => 100]),\n mkfile('passport.jpg', ['size' => 200]),\n mkfile('family.jpg', ['size' => 150]),\n mkfile('addresses', ['size' => 125]),\n mkdir('presentations')\n ]\n);\n\n$newTree = compressImages($tree);\n// То же самое, что и tree, но во всех картинках размер уменьшен в два раза\n```\n","prepared_readme":"## src/tree.php\n\nРеализуйте функцию `compressImages()`, которая принимает на вход директорию, находит внутри нее картинки и \"сжимает\" их. Под сжиманием понимается уменьшение свойства `size` в метаданных в два раза. Функция должна вернуть обновленную директорию со сжатыми картинками и всеми остальными данными, которые были внутри этой директории.\n\nКартинками считаются все файлы заканчивающиеся на *.jpg*.\n\n### Примеры\n\n```php\n<?php\n\nuse function Php\\Immutable\\Fs\\Trees\\trees\\mkdir;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\mkfile;\nuse function App\\tree\\compressImages;\n\n$tree = mkdir(\n 'my documents', [\n mkfile('avatar.jpg', ['size' => 100]),\n mkfile('passport.jpg', ['size' => 200]),\n mkfile('family.jpg', ['size' => 150]),\n mkfile('addresses', ['size' => 125]),\n mkdir('presentations')\n ]\n);\n\n$newTree = compressImages($tree);\n// То же самое, что и tree, но во всех картинках размер уменьшен в два раза\n```\n","has_solution":true,"entity_name":"Манипуляции с виртуальной файловой системой"},"units":[{"id":3772,"name":"theory","url":"/courses/php-trees/lessons/manipulations/theory_unit"},{"id":4040,"name":"quiz","url":"/courses/php-trees/lessons/manipulations/quiz_unit"},{"id":3789,"name":"exercise","url":"/courses/php-trees/lessons/manipulations/exercise_unit"}],"links":[],"ordered_units":[{"id":3772,"name":"theory","url":"/courses/php-trees/lessons/manipulations/theory_unit"},{"id":4040,"name":"quiz","url":"/courses/php-trees/lessons/manipulations/quiz_unit"},{"id":3789,"name":"exercise","url":"/courses/php-trees/lessons/manipulations/exercise_unit"}],"id":1732,"slug":"manipulations","state":"approved","name":"Манипуляции с виртуальной файловой системой","course_order":265,"goal":"Учимся изменять файловую систему в неизменяемом стиле","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Библиотека, которая используется для построения деревьев, рассчитана только на неизменяемые файловые структуры. То есть уже после создания ее поменять нельзя. Но можно на основе старой структуры сделать новую, в которой какие-то части будут изменены.\n\nНеизменяемая структура выбрана для этого курса не случайно. Такую структуру легче отлаживать и меньше шансов допустить ошибки. И она позволяет максимально погрузиться в использование функций высшего порядка.\n\n## Базовые операции с узлами\n\nПакет *php-immutable-fs-trees* позволяет не только создавать, но и извлекать данные из уже созданных файлов и директорий. Функции этой библиотеки позволяют не лезть во внутреннюю структуру самого дерева:\n\n```php\n<?php\n\nuse function Php\\Immutable\\Fs\\Trees\\trees\\mkdir;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\mkfile;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\getChildren;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\getName;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\getMeta;\n\n$tree = mkdir('/', [mkfile('hexlet.log')], ['hidden' => true]);\ngetName($tree); // '/'\ngetMeta($tree)['hidden']; // true\n\n[$file] = getChildren($tree);\ngetName($file); // 'hexlet.log'\nisset(getMeta($file)['unknown']); // false\n\n// А вот так делать не надо\n// У файлов нет детей\ngetChildren($file);\n```\n\nДополнительно в пакете есть две функции для проверки типа. С их помощью можно выборочно работать с файлами и директориями:\n\n```php\n<?php\n\nuse function Php\\Immutable\\Fs\\Trees\\trees\\mkdir;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\mkfile;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\getChildren;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\getName;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\getMeta;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\isDirectory;\nuse function Php\\Immutable\\Fs\\Trees\\trees\\isFile;\n\n$tree = mkdir('/', [mkfile('hexlet.log')], ['hidden' => true]);\nisDirectory($tree); // true\nisFile($tree); // false\n\n[$file] = getChildren($tree);\nisFile($file); // true\nisDirectory($file); // false\n```\n\nРассмотренных операций хватит для выполнения любых преобразований над файлами и директориями. Начнем с самых простых, которые не требуют рекурсивного обхода.\n\n## Обработка\n\nЛюбая обработка в неизменяемом стиле сводится к формированию новых данных на основе старых. Ниже мы реализуем некоторые варианты преобразования, раскрывающие эту идею.\n\n### Изменение имени файла\n\n```php\n<?php\n\n$file = mkfile('one', ['size' => 35]);\n$newFile = mkfile('new name', getMeta($file));\n```\n\nФактически здесь создается новый файл с метаданными старого.\n\n### Сортировка содержимого директории\n\n```php\n<?php\n\n// Сортировка в обратном порядке\n$tree = mkdir('/', [\n mkfile('one'),\n mkfile('two'),\n mkdir('three'),\n]);\n\n$children = getChildren($tree);\n$newChildren = array_reverse($children);\n$tree2 = mkdir(getName($tree), $newChildren, getMeta($tree));\n// [\n// 'name' => '/',\n// 'type' => 'directory',\n// 'meta' => [],\n// 'children' => [\n// ['name' => 'three', 'type' => 'directory', 'meta' => [], 'children' => []],\n// ['name' => 'two', 'type' => 'file', 'meta' => []],\n// ['name' => 'one', 'type' => 'file', 'meta' => []]\n// ]\n// ]\n```\n\n### Обновление содержимого директории\n\n```php\n<?php\n\n// Приведение к нижнему регистру имен директорий и файлов\n// внутри конкретной директории\n\n$tree = mkdir('/', [\n mkfile('oNe'),\n mkfile('Two'),\n mkdir('THREE'),\n]);\n\n$children = getChildren($tree);\n$newChildren = array_map(function ($child) {\n $name = getName($child);\n if (isDirectory($child)) {\n return mkdir(strtolower($name), getChildren($child), getMeta($child));\n }\n return mkfile(strtolower($name), getMeta($child));\n}, $children);\n\n$tree2 = mkdir(getName($tree), $newChildren, getMeta($tree));\n// [\n// 'name' => '/',\n// 'type' => 'directory',\n// 'meta' => [],\n// 'children' => [\n// ['name' => 'one', 'type' => 'file', 'meta' => []],\n// ['name' => 'two', 'type' => 'file', 'meta' => []],\n// ['name' => 'three', 'type' => 'directory', 'meta' => [], 'children' => []]\n// ]\n// ]\n```\n\n### Удаление файлов внутри директории\n\n```php\n<?php\n\n$tree = mkdir('/', [\n mkfile('one'),\n mkfile('two'),\n mkdir('three'),\n]);\n\n$children = getChildren($tree);\n$newChildren = array_filter($children, fn($child) => isDirectory($child));\n$tree2 = mkdir(getName($tree), $newChildren, getMeta($tree));\n// [\n// 'name' => '/',\n// 'type' => 'directory',\n// 'meta' => [],\n// 'children' => [\n// ['name' => 'three', 'type' => 'directory', 'meta' => [], 'children' => []]\n// ]\n// ]\n```\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":3587,"name":"theory","url":"/courses/php-trees/lessons/intro/theory_unit"}],"links":[{"id":424820,"name":"Рекурсия, рекурсивный процесс и итеративный процесс","url":"https://ru.hexlet.io/blog/posts/recursive"}],"ordered_units":[{"id":3587,"name":"theory","url":"/courses/php-trees/lessons/intro/theory_unit"}],"id":1666,"slug":"intro","state":"approved","name":"Введение","course_order":100,"goal":"Знакомимся с курсом и его целями","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Дерево — одна из самых распространенных структур данных в информатике и естественный способ моделирования некоторых предметных областей. С деревьями (как структурой данных) встречаются так или иначе все люди, даже те, кто далек не только от программирования, но и от компьютеров в целом. Самым очевидным примером служит генеалогическое древо, а из более специализированного — файловое дерево. HTML (а так же JSON, XML и многое другое) также имеет древовидную структуру. Комментарии и каталоги продуктов на сайтах тоже бывают древовидными. Любая иерархия является деревом по определению.\n\n\n\nС деревьями связан один очень интересный аспект. Уровень понимания темы деревьев и способность с ними работать невероятно сильно коррелирует с уровнем разработчика. Если разработчику легко работать с деревьями, то он довольно хорошо разбирается в своем и чужом коде, если нет — у него больше сложностей с написанием и анализом кода.\n\nВ этом курсе нет нового синтаксиса и каких-то элементов программирования, которые не изучались на Хекслете до этого курса. Однако тема деревьев сложнее остальных тем из-за рекурсивной природы самих деревьев. Нужно \"повернуть\" мозги в правильную сторону и это, пожалуй, самая тяжелая часть, которую невозможно «прокачать» читая теорию. В этом поможет только практика и эксперименты.\n\nДля упрощения процесса понимания и запоминания рекомендации такие же как и раньше:\n\n1. Обязательно повторяйте весь код, который дается в теории, локально на своем компьютере.\n1. Используйте отладочную печать настолько, насколько можно. Выводите на экран все изменения данных во время работы кода.\n\nВ этом небольшом курсе мы слегка погрузимся в тему деревьев и научимся с ними работать. Чего не будет в этом курсе, так это алгоритмов в том виде, в котором эта тема подается в университете. У данного курса совсем другие цели. Он учит работать с рекурсивными структурами данных через древовидную рекурсию.\n"},"id":205,"slug":"php-trees","challenges_count":8,"name":"PHP: Деревья","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы изучите работу с деревьями в PHP. Вы узнаете о рекурсивных структурах данных, обходе в глубину и древовидной рекурсии. В итоге разберетесь в том, как деревья устроены изнутри. Деревья пригодятся при работе с категориями товаров, комментариями, HTML, XML, JSON.","kind":"advanced","updated_at":"2026-01-20T11:50:13.944Z","language":"php","duration_cache":38700,"skills":["Разбираться в принципах устройства и построении деревьев","Представлять в коде и обрабатывать данные имеющие рекурсивную природу, например файловую систему, каталоги или деревья комментариев","Строить абстракции поверх древовидных структур данных","Использовать функциональную парадигму"],"keywords":["рекурсивные структуры данных","обход в глубину","древовидная рекурсия","файловая система"],"lessons_count":9,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6ODE1NSwicHVyIjoiYmxvYl9pZCJ9fQ==--51a38045dd088d4d6d12aa0ccf7029ccc2ac052f/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJqcGciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--39ba06fa99226096df9fc6bb31f84e1d29ea98e9/image.png"},"recommendedLandings":[{"stack":{"id":2,"slug":"php","title":"PHP-разработчик","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":60,"duration_in_months":10},"id":1,"slug":"php","title":"РНР-разработчик","subtitle":"Изучите PHP и Laravel для разработки и проектирования REST API","subtitle_for_lists":"Изучите PHP и Laravel для разработки и проектирования REST API","locale":"ru","current":true,"duration_in_months_text":"10 месяцев","stack_slug":"php","price_text":"от 5 650 ₽","duration_text":"10 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk5MiwicHVyIjoiYmxvYl9pZCJ9fQ==--e9d0f30948ea766a7e6bc3e3d56c192344d45fb8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programming-cuate%20(1).png"}],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/php-trees/lessons/manipulations/theory_unit","version":"8f286f6358a90a7bef2263b3a6edf5a90a94fa42","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><div style="position:absolute;top:0rem" class=""></div><div style="max-width:var(--container-size-xl);height:100%;min-height:0rem" class=""><style data-mantine-styles="inline">.__m__-_R_5ub_{--grid-gutter:0rem;}</style><div style="height:100%;min-height:0rem" class="m_410352e9 mantine-Grid-root __m__-_R_5ub_"><div class="m_dee7bd2f mantine-Grid-inner" style="height:100%"><style data-mantine-styles="inline">.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:91.66666666666667%;--col-max-width:91.66666666666667%;}@media(min-width: 48em){.__m__-_R_rdub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem;display:flex" class="m_96bdd299 mantine-Grid-col __m__-_R_rdub_"><style data-mantine-styles="inline">.__m__-_R_6qrdub_{margin-top:0rem;padding-inline:var(--mantine-spacing-xs);width:100%;}@media(min-width: 48em){.__m__-_R_6qrdub_{margin-top:var(--mantine-spacing-xl);width:80%;}}@media(min-width: 62em){.__m__-_R_6qrdub_{padding-inline:var(--mantine-spacing-xl);}}</style><div style="margin-inline:auto;max-width:var(--mantine-breakpoint-xl)" class="__m__-_R_6qrdub_"><div style="color:var(--mantine-color-dimmed)" class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:calc(0.125rem * var(--mantine-scale));color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-lock "><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"></path><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"></path><path d="M8 11v-4a4 4 0 1 1 8 0v4"></path></svg></div><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">PHP: Деревья</p></div><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size);margin-bottom:var(--mantine-spacing-xl)" class="m_8a5d1357 mantine-Title-root" data-order="1">Теория: Манипуляции с виртуальной файловой системой</h1><script type="application/ld+json">{"@context":"https://schema.org","@type":"LearningResource","name":"Манипуляции с виртуальной файловой системой","inLanguage":"ru","isPartOf":{"@type":"LearningResource","name":"PHP: Деревья"},"isAccessibleForFree":"False","hasPart":{"@type":"WebPageElement","isAccessibleForFree":"False","cssSelector":".paywalled"}}</script><div class=""><div style="--alert-color:var(--mantine-color-indigo-light-color);margin-bottom:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-lg)" class="m_66836ed3 mantine-Alert-root" id="mantine-_R_remqrdub_" role="alert" aria-describedby="mantine-_R_remqrdub_-body" aria-labelledby="mantine-_R_remqrdub_-title"><div class="m_a5d60502 mantine-Alert-wrapper"><div class="m_667f2a6a mantine-Alert-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-rocket "><path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"></path><path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"></path><path d="M14 9a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path></svg></div><div class="m_667c2793 mantine-Alert-body"><div class="m_6a03f287 mantine-Alert-title"><span id="mantine-_R_remqrdub_-title" class="m_698f4f23 mantine-Alert-label">Полный доступ к материалам</span></div><div id="mantine-_R_remqrdub_-body" class="m_7fa78076 mantine-Alert-message"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Зарегистрируйтесь и получите доступ к этому и десяткам других курсов</p><a style="--button-height:var(--button-height-xs);--button-padding-x:var(--button-padding-x-xs);--button-fz:var(--mantine-font-size-xs);--button-bg:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-hover:linear-gradient(45deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-filled) 100%);--button-color:var(--mantine-color-white);--button-bd:none" class="mantine-focus-auto mantine-active m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root" data-variant="gradient" data-size="xs" href="/u/new"><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">Зарегистрироваться</span></span></a></div></div></div></div></div><div class="paywalled m_d08caa0 mantine-Typography-root"><p>Библиотека, которая используется для построения деревьев, рассчитана только на неизменяемые файловые структуры. То есть уже после создания ее поменять нельзя. Но можно на основе старой структуры сделать новую, в которой какие-то части будут изменены.</p>
<p>Неизменяемая структура выбрана для этого курса не случайно. Такую структуру легче отлаживать и меньше шансов допустить ошибки. И она позволяет максимально погрузиться в использование функций высшего порядка.</p>
<h2 id="heading-2-1">Базовые операции с узлами</h2>
<p>Пакет <em>php-immutable-fs-trees</em> позволяет не только создавать, но и извлекать данные из уже созданных файлов и директорий. Функции этой библиотеки позволяют не лезть во внутреннюю структуру самого дерева:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code"><?php
use function Php\Immutable\Fs\Trees\trees\mkdir;
use function Php\Immutable\Fs\Trees\trees\mkfile;
use function Php\Immutable\Fs\Trees\trees\getChildren;
use function Php\Immutable\Fs\Trees\trees\getName;
use function Php\Immutable\Fs\Trees\trees\getMeta;
$tree = mkdir('/', [mkfile('hexlet.log')], ['hidden' => true]);
getName($tree); // '/'
getMeta($tree)['hidden']; // true
[$file] = getChildren($tree);
getName($file); // 'hexlet.log'
isset(getMeta($file)['unknown']); // false
// А вот так делать не надо
// У файлов нет детей
getChildren($file);</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Дополнительно в пакете есть две функции для проверки типа. С их помощью можно выборочно работать с файлами и директориями:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code"><?php
use function Php\Immutable\Fs\Trees\trees\mkdir;
use function Php\Immutable\Fs\Trees\trees\mkfile;
use function Php\Immutable\Fs\Trees\trees\getChildren;
use function Php\Immutable\Fs\Trees\trees\getName;
use function Php\Immutable\Fs\Trees\trees\getMeta;
use function Php\Immutable\Fs\Trees\trees\isDirectory;
use function Php\Immutable\Fs\Trees\trees\isFile;
$tree = mkdir('/', [mkfile('hexlet.log')], ['hidden' => true]);
isDirectory($tree); // true
isFile($tree); // false
[$file] = getChildren($tree);
isFile($file); // true
isDirectory($file); // false</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Рассмотренных операций хватит для выполнения любых преобразований над файлами и директориями. Начнем с самых простых, которые не требуют рекурсивного обхода.</p>
<h2 id="heading-2-2">Обработка</h2>
<p>Любая обработка в неизменяемом стиле сводится к формированию новых данных на основе старых. Ниже мы реализуем некоторые варианты преобразования, раскрывающие эту идею.</p>
<h3 id="heading-3-3">Изменение имени файла</h3>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code"><?php
$file = mkfile('one', ['size' => 35]);
$newFile = mkfile('new name', getMeta($file));</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Фактически здесь создается новый файл с метаданными старого.</p>
<h3 id="heading-3-4">Сортировка содержимого директории</h3>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code"><?php
// Сортировка в обратном порядке
$tree = mkdir('/', [
mkfile('one'),
mkfile('two'),
mkdir('three'),
]);
$children = getChildren($tree);
$newChildren = array_reverse($children);
$tree2 = mkdir(getName($tree), $newChildren, getMeta($tree));
// [
// 'name' => '/',
// 'type' => 'directory',
// 'meta' => [],
// 'children' => [
// ['name' => 'three', 'type' => 'directory', 'meta' => [], 'children' => []],
// ['name' => 'two', 'type' => 'file', 'meta' => []],
// ['name' => 'one', 'type' => 'file', 'meta' => []]
// ]
// ]</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<h3 id="heading-3-5">Обновление содержимого директории</h3>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code"><?php
// Приведение к нижнему регистру имен директорий и файлов
// внутри конкретной директории
$tree = mkdir('/', [
mkfile('oNe'),
mkfile('Two'),
mkdir('THREE'),
]);
$children = getChildren($tree);
$newChildren = array_map(function ($child) {
$name = getName($child);
if (isDirectory($child)) {
return mkdir(strtolower($name), getChildren($child), getMeta($child));
}
return mkfile(strtolower($name), getMeta($child));
}, $children);
$tree2 = mkdir(getName($tree), $newChildren, getMeta($tree));
// [
// 'name' => '/',
// 'type' => 'directory',
// 'meta' => [],
// 'children' => [
// ['name' => 'one', 'type' => 'file', 'meta' => []],
// ['name' => 'two', 'type' => 'file', 'meta' => []],
// ['name' => 'three', 'type' => 'directory', 'meta' => [], 'children' => []]
// ]
// ]</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<h3 id="heading-3-6">Удаление файлов внутри директории</h3>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code"><?php
$tree = mkdir('/', [
mkfile('one'),
mkfile('two'),
mkdir('three'),
]);
$children = getChildren($tree);
$newChildren = array_filter($children, fn($child) => isDirectory($child));
$tree2 = mkdir(getName($tree), $newChildren, getMeta($tree));
// [
// 'name' => '/',
// 'type' => 'directory',
// 'meta' => [],
// 'children' => [
// ['name' => 'three', 'type' => 'directory', 'meta' => [], 'children' => []]
// ]
// ]</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div></div><div style="margin-block:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Рекомендуемые программы</h2><style data-mantine-styles="inline">.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:70%;}@media(min-width: 36em){.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_2mremqrdub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/php?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">10 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">РНР-разработчик</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите PHP и Laravel для разработки и проектирования REST API</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk5MiwicHVyIjoiYmxvYl9pZCJ9fQ==--e9d0f30948ea766a7e6bc3e3d56c192344d45fb8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programming-cuate%20(1).png" alt="РНР-разработчик" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 5 650 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md);font-size:var(--mantine-font-size-h3)" class="m_8a5d1357 mantine-Title-root" data-order="2" data-responsive="true">Каталог</h2><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Полный список доступных курсов по разным направлениям</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="/vite/assets/development-BVihs_d5.png" alt="Orientation"/></div></div></div></a></div></div></div></div></div></div></div></div></div><style data-mantine-styles="inline">.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:8.333333333333334%;--col-max-width:8.333333333333334%;}@media(min-width: 48em){.__m__-_R_1bdub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}</style><div style="min-width:0rem;height:100%;min-height:0rem" class="m_96bdd299 mantine-Grid-col __m__-_R_1bdub_"><div style="margin-inline:var(--mantine-spacing-xs)" class="mantine-visible-from-sm"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-lg);text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/php-trees/lessons/manipulations/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label"><span style="margin-inline-end:var(--mantine-spacing-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Дальше</span>→</span></span></a><a style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Навигация по теме</span><span class="m_57492dcc mantine-NavLink-description">Теория</span></div><span class="m_690090b5 mantine-NavLink-section" data-position="right"></span></a><div style="margin-block:var(--mantine-spacing-lg)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div><div style="margin-block:var(--mantine-spacing-lg)" class=""><div style="justify-content:space-between;margin-bottom:calc(0.1875rem * var(--mantine-scale));color:var(--mantine-color-dimmed);font-size:var(--mantine-font-size-xs)" class="m_8bffd616 mantine-Flex-root __m__-_R_qimrbdub_"><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Завершено</p><p style="font-size:var(--mantine-font-size-xs)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">0 / 9</p></div><div style="--progress-size:var(--progress-size-sm)" class="m_db6d6462 mantine-Progress-root" data-size="sm"><div style="--progress-section-size:0%;--progress-section-color:var(--mantine-color-gray-filled)" class="m_2242eb65 mantine-Progress-section" role="progressbar" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" aria-valuetext="0%"></div></div></div><button style="padding-inline:0rem" class="mantine-focus-auto m_f0824112 mantine-NavLink-root m_87cf2631 mantine-UnstyledButton-root" type="button"><span class="m_690090b5 mantine-NavLink-section" data-position="left"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></div></span><div class="m_f07af9d2 mantine-NavLink-body"><span class="m_1f6ac4c4 mantine-NavLink-label">Обсуждения (архив)</span><span class="m_57492dcc mantine-NavLink-description"></span></div></button><div style="--toc-bg:var(--mantine-color-blue-light);--toc-color:var(--mantine-color-blue-light-color);--toc-size:var(--mantine-font-size-sm);--toc-radius:var(--mantine-radius-sm);margin-top:var(--mantine-spacing-xl)" class="m_bcaa9990 mantine-TableOfContents-root" data-variant="light" data-size="sm"></div></div><div class="mantine-hidden-from-sm"><div style="--stack-gap:0rem;--stack-align:stretch;--stack-justify:flex-start" class="m_6d731127 mantine-Stack-root"><a style="--button-color:var(--mantine-color-white);margin-bottom:var(--mantine-spacing-xs);padding:0rem;text-decoration:none" class="mantine-focus-auto m_849cf0da mantine-focus-auto m_77c9d27d mantine-Button-root m_87cf2631 mantine-UnstyledButton-root m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses/php-trees/lessons/manipulations/finish_unit?unit=theory" data-disabled="true" data-block="true" disabled=""><span class="m_80f1301b mantine-Button-inner"><span class="m_811560b9 mantine-Button-label">→</span></span></a><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" data-disabled="true" type="button" disabled=""><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-list-numbers "><path d="M11 6h9"></path><path d="M11 12h9"></path><path d="M12 18h8"></path><path d="M4 16a2 2 0 1 1 4 0c0 .591 -.5 1 -1 1.5l-3 2.5h4"></path><path d="M6 10v-6l-2 2"></path></svg></span></button><button style="--ai-size:var(--ai-size-sm);--ai-bg:transparent;--ai-hover:var(--mantine-color-indigo-light-hover);--ai-color:var(--mantine-color-indigo-light-color);--ai-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding-block:var(--mantine-spacing-lg);color:inherit;width:100%" class="mantine-focus-auto mantine-active m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="subtle" data-size="sm" type="button"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-message "><path d="M8 9h8"></path><path d="M8 13h6"></path><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"></path></svg></span></button></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-Bukl1lYy.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>