<!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 20:42:19 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="wwS8BRobxf3omUvh60Xxl0Aj6J3oog8FSQUP4Hl2sgss1Xcy6GVonV7ab3nnSgHggCrFN-CV8af05ZW0K3FVZQ";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-functions/lessons/signals/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-functions/lessons/signals/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="vTFBngAMjYnT0UFValFrIPQJaYlxrycr_Tv2OU71ghZS4Iqp8nIg6WWSZc1mXptXNABEI3mY2YlA22xtHPJleA" />
<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-26T20:42:19.534Z","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":"4aUWUDTgwIAJyuRO1L_9a2ZrAAggN7ka7EB3RXMyaCsOdN1nxp5t4L-JwNbYsA0cpmItoigAR7hRoO0RITWPRQ","topics":[{"id":20379,"title":"У меня получилось как-то совсем нет так, как в решении учителя. Возможно решение получилось не по теме урока. Прокомментируйте пожалуйста для меня мой вариант решения. https://ru.hexlet.io/code_reviews/70021?submission_id=94437 Второй вариант.","plain_title":"У меня получилось как-то совсем нет так, как в решении учителя. Возможно решение получилось не по теме урока. Прокомментируйте пожалуйста для меня мой вариант решения. https://ru.hexlet.io/codereviews/70021?submissionid=94437 Второй вариант. ","creator":{"public_name":"Anatol Meshalkin","id":167557,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":43145,"body":"Здравствуйте!\n\n> У меня получилось как-то совсем нет так, как в решении учителя. \n\nВы сопоставляли свой код с учительским? Опишите, какие сходства и отличия вы видите","topic_id":20379},{"creator":{"public_name":"Anatol Meshalkin","id":167557,"is_tutor":false},"id":43149,"body":"Сходство в том, что у обеих функций одинаковая архитектура.\nРазличие в реализации. У вас последовательно применены функции map, filter и reduce, т.е. по всем темам, что мы только что изучали. А я использовал другие функции из той же стандартной библиотеки PHP. При решении задачи, я преследовал только одну цель - решить задачу теми средствами, которым вы меня научили. Как по вашему, у меня получилось или нет?\n","topic_id":20379},{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":43181,"body":"`explode('@', implode($emails, '@'));` - а что делает это выражение?","topic_id":20379},{"creator":{"public_name":"Anatol Meshalkin","id":167557,"is_tutor":false},"id":43188,"body":"Да, не так эффективно, и промежуточные результаты более хаотичные. Я все понял, спасибо. Ваш код полностью логичен, мой же просто выдает правильный ответ, но результаты первой и второй функции довольно хаотичны. Еще раз спасибо.","topic_id":20379}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":48253,"title":"Здравствуйте! В уроке \"Сигналы\" функция getPHPFileNames реализованная через array_filter и array_map должна получить такой же результат как и с реализацией через foreach?","plain_title":"Здравствуйте! В уроке \"Сигналы\" функция getPHPFileNames реализованная через arrayfilter и arraymap должна получить такой же результат как и с реализацией через foreach? ","creator":{"public_name":"Артур Нутфуллин","id":285530,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":103665,"body":"Приветствую, Артур!\n\nДа. Это одна и та же функция, отличается лишь внутренняя реализация. Результат будет совпадать. Я добавил комментарии во второй пример.","topic_id":48253},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":103896,"body":"Данный пример иллюстрирует декомпозицию задачи на фильтрацию и отображение. В итоге нам нужно получить только имена файлов. Для упрощения примера массив путей как раз содержит имена и вы правы говоря о том, что в таком варианте можно просто отфильтровать массив по расширениям. Но в реальности массив может содержать пути вида _directory1/directory2/file.php_ и в этом случае простой фильтрацией будет уже не обойтись.","topic_id":48253},{"creator":{"public_name":"Артур Нутфуллин","id":285530,"is_tutor":false},"id":103777,"body":"Мне кажется нужно проверить второй пример на корректную работу. Вообщем замысел и суть второго примера понятен в рамках урока.\n\nЕсли результат такой же как и у первого примера, тогда можно обойтись одним array_filter и из return убрать is_file($path).\nУбрать строчку с array_map и дописать return $phpFiles;.","topic_id":48253}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":19669,"title":"[Решил](https://ru.hexlet.io/code_reviews/66791) через регулярные выражения, хотя до конца и не понял как это получилось. Посмотрел решение учителя. Это круто! Разделить через `explode` и вернуть вторую часть. Очень интересно.\n","plain_title":"Решил (https://ru.hexlet.io/code_reviews/66791) через регулярные выражения, хотя до конца и не понял как это получилось. Посмотрел решение учителя. Это круто! Разделить через explode и вернуть вторую часть. Очень интересно. ","creator":{"public_name":"Станислав Муратшин","id":157440,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":41547,"body":":)","topic_id":19669},{"creator":{"public_name":"Артем","id":168956,"is_tutor":false},"id":95926,"body":"**Станислав Муратшин**, спасибо за подсказку :). Не хотелось изобретать велосипед по поиску подстроки в строке :)","topic_id":19669}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":38672,"title":"Вопрос по тесту, не понятно почему правильный ответ: mapping?\n\nКакую операцию необходимо применить в данной ситуации:\n\n```\nНаучить играть в футбол школьный класс\n```\n\n","plain_title":"Вопрос по тесту, не понятно почему правильный ответ: mapping? Какую операцию необходимо применить в данной ситуации: Научить играть в футбол школьный класс ","creator":{"public_name":"Damir Sarkulin","id":159701,"is_tutor":false},"comments":[{"creator":{"public_name":"Bogdan Fedorkovsky","id":191470,"is_tutor":false},"id":90495,"body":"**Roman Kozlov**, но до того как обучить, нужно знать кого обучать. Поэтому сразу идёт отображение учеников класса, тех кого нужно научить играть в футбол.","topic_id":38672},{"creator":{"public_name":"Roman Kozlov","id":231814,"is_tutor":false},"id":84510,"body":"Добрый день! \nИмеется ввиду, что на выходе получается школьный класс обученный играть в футбол. Каждый необученный ученник отображается в обученного. ","topic_id":38672}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":32060,"title":"На [repl.it](https://repl.it/@EvgenyPavlov/hexlet-php-functions-signals) все работает исправно. Но тут получаю ошибку:\n\n> 1) App\\Tests\\EmailsTest::testGetFreeDomainsCount\n> null does not match expected type \"array\".\n> \n> /usr/src/app/tests/EmailsTest.php:23\n> \nНе могу понять в чем проблема. \n\n```\nfunction getFreeDomainsCount($emails) \n{\n\t$domain = array_map (function ($mail) {\n\t\treturn preg_replace('/^.+?@/', '',$mail);\n\t}, $emails);\n\n\t$filtered_emails = array_filter ($domain, function ($mail) {\n\t\tif (in_array($mail, FREE_EMAIL_DOMAINS)) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t});\n\n\t$map_emails = array_reduce ($filtered_emails, function ($acc, $mail) {\n\t\t$acc[$mail] = $acc[$mail] + 1;\n\t\treturn $acc;\n\t});\n\n\treturn $map_emails;\n\n}\n```","plain_title":"На repl.it (https://repl.it/@EvgenyPavlov/hexlet-php-functions-signals) все работает исправно. Но тут получаю ошибку: 1) App\\Tests\\EmailsTest::testGetFreeDomainsCount null does not match expected type \"array\". /usr/src/app/tests/EmailsTest.php:23 Не могу понять в чем проблема. ```function getFreeDomainsCount($emails) { $domain = arraymap (function ($mail) { return pregreplace('/^.+?@/', '',$mail); }, $emails); $filtered_emails = array_filter ($domain, function ($mail) { if (in_array($mail, FREE_EMAIL_DOMAINS)) { return true; } else { return false; } }); $map_emails = array_reduce ($filtered_emails, function ($acc, $mail) { $acc[$mail] = $acc[$mail] + 1; return $acc; }); return $map_emails; }``` ","creator":{"public_name":"Evgeny Pavlov","id":181127,"is_tutor":false},"comments":[{"creator":{"public_name":"Nikita Mikhaylov","id":186965,"is_tutor":true},"id":69730,"body":"Здравствуйте\n\nОбратите внимание на `array_reduce`. Какой начальный аккумулятор у вас используется? Ошибка же говорит о том, что ожидается возвращению из функции массива, но вернулся `null`","topic_id":32060}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":48469,"title":"ввел первый пример из теории на интерпретаторе шторма он выводит пустой массив","plain_title":"ввел первый пример из теории на интерпретаторе шторма он выводит пустой массив ","creator":{"public_name":"Ying Yang","id":308046,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":104121,"body":"Приветствую!\n\nВладимир верно ответил на ваш вопрос. Всё дело в отсутствии файлов по переданным путям. Если вам помог его ответ, то можно нажать на кнопку \"Отметить как решение\" и таким образом поблагодарить его за помощь. А еще это помогает другим студентам в поисках ответов на похожие вопросы.","topic_id":48469},{"creator":{"public_name":"Vladimir Minkin","id":248254,"is_tutor":false},"id":104080,"body":"**Ardo Yang**, в этом примере используется функция is_file, которая проверяет реальное существование файла по переданному пути. Так как этих файлов нет в вашей системе (в папке, рядом с исполняемым файлом), то она везде отвечает false, и условие не выполняется. Таким образом вы получаете на выходе пустой массив, который задается в начале функции!","topic_id":48469}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":30649,"title":"доброго времени суток, уважаемые менторы! а как вообще работать с константами, и для чего нам дана константа FREE_EMAIL_DOMAINS в упражнении? константу можно использовать как переменную, только она не будет меняться в процессе выполнения кода? и можно ли нашу константу использовать как опцию к функции pathinfo (возникла ассоциация, так как стандарт именования констант такой же как и опции (прим: PATHINFO_EXTENSION или PATHINFO_BASENAME)) ? хотя про использование констант как опции я загнул конечно, вряд ли это возможно, но все равно интересно ","plain_title":"доброго времени суток, уважаемые менторы! а как вообще работать с константами, и для чего нам дана константа FREEEMAILDOMAINS в упражнении? ","creator":{"public_name":"Yaroslav Volkov","id":199364,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":66503,"body":"Приветствую!\n\n> а как вообще работать с константами\n\nПосмотрите наш урок про константы https://code-basics.ru/languages/php/modules/variables/lessons/constants\n\n> и для чего нам дана константа FREE_EMAIL_DOMAINS в упражнении?\n\nВ ней содержится список бесплатных доменов. Эта информация используется функцией, которую надо реализовать в задании.\n\n> и можно ли нашу константу использовать как опцию к функции pathinfo (возникла ассоциация, так как стандарт именования констант такой же как и опции (прим: PATHINFO_EXTENSION или PATHINFO_BASENAME)) ?\n\nПробуйте делать по-разному, экспериментируйте, у вас нет здесь ограничений. Потом можете сравнить своё решение с учительским.","topic_id":30649}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":20813,"title":"Помогите пожалуйста справиться с этим заданием.\n\nНикакие мысли в голову не лезут :( точнее как эту константу ```const FREE_EMAIL_DOMAINS = [\n 'gmail.com', 'yandex.ru', 'hotmail.com'\n];``` использовать? ","plain_title":"Помогите пожалуйста справиться с этим заданием. Никакие мысли в голову не лезут :( точнее как эту константу const FREE_EMAIL_DOMAINS = [ 'gmail.com', 'yandex.ru', 'hotmail.com' ]; использовать? ","creator":{"public_name":"Damir Sarkulin","id":159701,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":44105,"body":"Добрый день!\n\n> точнее как эту константу const FREE_EMAIL_DOMAINS = [ 'gmail.com', 'yandex.ru', 'hotmail.com' ]; использовать?\n\nЭта константа хранит список бесплатных доменов. С помощью неё можно делать проверку располагается ли email (переданный во входном списке) в бесплотном домене или нет.","topic_id":20813}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":43709,"title":"Добрый день!\n\nПочему урок называется \"Сигналы\", если там описание стандартных интерфейсов, и даже слово \"сигналы\" в нём ни разу не встречается? :)\nТолько в дополнительных материалах ссылка на статью про обработку сигналов.","plain_title":"Добрый день! Почему урок называется \"Сигналы\", если там описание стандартных интерфейсов, и даже слово \"сигналы\" в нём ни разу не встречается? :) Только в дополнительных материалах ссылка на статью про обработку сигналов. ","creator":{"public_name":"Denis Skvortsov","id":185650,"is_tutor":false},"comments":[{"creator":{"public_name":"Denis Skvortsov","id":185650,"is_tutor":false},"id":95006,"body":"> Но осмелюсь предположить, что смысл в сравнении с аналогвым сигналом. \n\nДа, я тоже так думаю, вашего пояснения вполне хватило бы в предисловии к уроку. Просто сейчас к сравнению с обработкой сигналов можно прийти только после чтения вспомогательной статьи в Википедии, приведенной в дополнении к основному уроку после всего основного материала.\n\nЯ просто почему задал вопрос-то. \nКогда проходил этот урок, то название даже не заметил, главное - суть. А потом в будущих лекциях об ООП увидел ссылку на вспомогательный урок \"Сигналы\", он отмечен пройденным у меня, а по названию я даже не мог понять, что за ещё за сигналы в PHP мы проходили. А оказалось, что это урок о стандартных интерфейсах :)","topic_id":43709},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":95153,"body":"> Обработка сигналов — область радиотехники, в которой осуществляется восстановление, разделение информационных потоков, подавление шумов, сжатие данных, фильтрация, усиление сигналов.\n\nТо есть при таком подходе используются те же принципы, что и в обработке сигналов. Мы берем ток (данные) и пропускаем сквозь цепочку преобразователей (функций). Получается этакий пайплайн.","topic_id":43709},{"creator":{"public_name":"Ivan Gagarinov","id":75907,"is_tutor":true},"id":94995,"body":"Добрый день! Я не автор курса, и не придумывал название. Но осмелюсь предположить, что смысл в сравнении с аналогвым сигналом. То, как он обрабатывается: сначала фильтруются шумы, затем идет интерпретация сигнала, потом еще какие-то работы. Все эти процессы происходят раздельно и по порядку. Это схоже с тем, как описывается обработка коллекции в уроке: вместо одного цикла, в котором происходит все работа, несколько циклов(процессов) обработки.","topic_id":43709}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}},{"id":27344,"title":"`// removed`\n\nОбъясните, пожалуйста, как так может быть, что в PHP Storm и на Repl.it функция работает, а на сайте не проходит проверку и код не исполняется?\nСпасибо!","plain_title":"// removed Объясните, пожалуйста, как так может быть, что в PHP Storm и на Repl.it функция работает, а на сайте не проходит проверку и код не исполняется? Спасибо! ","creator":{"public_name":"Александр Горячев","id":225486,"is_tutor":false},"comments":[{"creator":{"public_name":"Сергей К.","id":5174,"is_tutor":false},"id":58588,"body":"Александр, обратите внимание, что [вернёт функция](https://www.php.net/manual/ru/function.array-reduce.php#refsect1-function.array-reduce-returnvalues), если ей передать пустой массив.","topic_id":27344},{"creator":{"public_name":"Александр Горячев","id":225486,"is_tutor":false},"id":58581,"body":"Я нашел причину, но по факту этот параметр не является необходимым и обязательным для array_reduce","topic_id":27344}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Цепочка операций","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":708,"slug":"php_functions_signals_exercise","name":null,"state":"active","kind":"exercise","language":"php","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"### src\\Emails.php\n\nРеализуйте функцию `getFreeDomainsCount`, которая принимает на вход список емейлов, а возвращает количество емейлов, расположенных на каждом бесплатном домене. Список бесплатных доменов хранится в константе `FREE_EMAIL_DOMAINS`.\n\n#### Пример использования\n\n```php\n<?php\n\n$emails = [\n 'info@gmail.com',\n 'info@yandex.ru',\n 'info@hotmail.com',\n 'mk@host.com',\n 'support@hexlet.io',\n 'key@yandex.ru',\n 'sergey@gmail.com',\n 'vovan@gmail.com',\n 'vovan@hotmail.com'\n];\n\ngetFreeDomainsCount($emails);\n# Array (\n# 'gmail.com' => 3\n# 'yandex.ru' => 2\n# 'hotmail.com' => 2\n# )\n```\n","prepared_readme":"### src\\Emails.php\n\nРеализуйте функцию `getFreeDomainsCount`, которая принимает на вход список емейлов, а возвращает количество емейлов, расположенных на каждом бесплатном домене. Список бесплатных доменов хранится в константе `FREE_EMAIL_DOMAINS`.\n\n#### Пример использования\n\n```php\n<?php\n\n$emails = [\n 'info@gmail.com',\n 'info@yandex.ru',\n 'info@hotmail.com',\n 'mk@host.com',\n 'support@hexlet.io',\n 'key@yandex.ru',\n 'sergey@gmail.com',\n 'vovan@gmail.com',\n 'vovan@hotmail.com'\n];\n\ngetFreeDomainsCount($emails);\n# Array (\n# 'gmail.com' => 3\n# 'yandex.ru' => 2\n# 'hotmail.com' => 2\n# )\n```\n","has_solution":true,"entity_name":"Цепочка операций"},"units":[{"id":2277,"name":"theory","url":"/courses/php-functions/lessons/signals/theory_unit"},{"id":2317,"name":"quiz","url":"/courses/php-functions/lessons/signals/quiz_unit"},{"id":2296,"name":"exercise","url":"/courses/php-functions/lessons/signals/exercise_unit"}],"links":[{"id":423262,"name":"Обработка сигналов","url":"https://ru.wikipedia.org/wiki/Обработка_сигналов"},{"id":423263,"name":"Продуманная оптимизация","url":"http://optimization.guide/"}],"ordered_units":[{"id":2277,"name":"theory","url":"/courses/php-functions/lessons/signals/theory_unit"},{"id":2317,"name":"quiz","url":"/courses/php-functions/lessons/signals/quiz_unit"},{"id":2296,"name":"exercise","url":"/courses/php-functions/lessons/signals/exercise_unit"}],"id":1083,"slug":"signals","state":"approved","name":"Цепочка операций","course_order":650,"goal":"Знакомимся с концепцией стандартных интерфейсов","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Пример с `usort()` хорошо демонстрирует важность и удобство функций высшего порядка для решения повседневных задач. Описав алгоритм один раз, мы можем получать различные варианты поведения, специфицируя их функциями. То же самое относится к рассмотренным функциям `map()`, `filter()` и `reduce()`. Но есть еще один важный аспект, который требует рассмотрения.\n\nТипичный код на PHP выглядит так: программа делает один цикл, внутри которого выполняются сразу все операции. В конце получается некоторый интересующий нас результат. Ничего криминального, но такой код сложно анализировать, потому что приходится держать в голове сразу все операции. С другой стороны, при использовании функций высшего порядка принято разделять задачу на подзадачи и выполнять их последовательно друг за другом, выстраивая в цепочку операций.\n\nВ [СИКП](https://guides.hexlet.io/ru/how-to-learn-sicp/) такой подход сравнивают с тем, как происходит [обработка сигналов](https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%81%D0%B8%D0%B3%D0%BD%D0%B0%D0%BB%D0%BE%D0%B2) при проектировании электросхем. Ток, протекая по схеме, проходит через цепочку преобразователей: фильтров, подавителей шума, усилителей и так далее. Напряжение (и создаваемый им ток) в этом случае выполняет роль данных, а преобразователи – роль функций.\n\n\n\nПредставим функцию, которая принимает на вход список путей файловой системы, находит среди них файлы с расширением *.php* без учета регистра и возвращает имена этих файлов. Для решения этой задачи понадобятся следующие функции:\n\n* `is_file()` проверяет, что переданный путь — это реально существующий файл\n* `pathinfo()` позволяет извлекать расширение из имени файла\n* `basename()` извлекает имя файла из полного пути\n\nКод выглядит так:\n\n```php\n<?php\n\nfunction getPHPFileNames(array $paths)\n{\n $result = [];\n foreach ($paths as $path) {\n $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));\n if (is_file($path) && $extension === 'php') {\n $result[] = basename($path);\n }\n }\n\n return $result;\n}\n\n$names = getPHPFileNames(['index.php', 'wop.PHP', 'nonexists', 'node_modules']);\nprint_r($names);\n// => Array\n// (\n// [0] => index.php\n// [1] => wop.PHP\n// )\n```\n\nВ примере выше вы видите типовое решение с использованием цикла. Его алгоритм можно описать так:\n\n1. Просматриваем каждый путь\n1. Если текущий путь — файл с расширением `php` (без учета регистра), то добавляем его имя в результирующий массив\n\nЕсли попытаться то же самое реализовать через функцию `array_reduce()`, то на выходе получится код, идентичный решению на циклах. Но если хорошо подумать, то эта задача распадается на две — фильтрацию и отображение:\n\n```php\n<?php\n\nfunction getPHPFileNames(array $paths)\n{\n // Фильтруем, оставляя только подходящие пути\n $phpFiles = array_filter($paths, function ($path) {\n $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));\n return is_file($path) && $extension === 'php';\n });\n\n // Извлекаем имена файлов из оставшихся путей и возвращаем их наружу\n return array_map(fn($path) => basename($path), $phpFiles);\n}\n\n$names = getPHPFileNames(['index.php', 'wop.PHP', 'nonexists', 'node_modules']);\nprint_r($names);\n// => Array\n// (\n// [0] => index.php\n// [1] => wop.PHP\n// )\n```\n\nКод получился чуть короче, но и многословнее — это исключительно особенность PHP. Тем не менее здесь размер не принципиален. С увеличением количества операций и их сложности такой код читается и анализируется значительно проще, потому что каждая операция выполняется независимо для всего набора сразу. В голове приходится держать меньше деталей, можно сразу увидеть то, как операция влияет на все данные. Но научиться правильно разбивать задачу на подзадачи не так просто, как может показаться. Нужна некоторая практика и сноровка перед тем, как ваш код станет удобоваримым.\n\n\n\nСама возможность такого разбиения основывается на простой идее, которую иногда называют **стандартные интерфейсы**. Эта идея заключается в том, что на входе и выходе из функций ожидается один и тот же тип данных в нашем случае, это массив. Это позволяет соединять функции и строить цепочки, выполняющие большое количество разных задач, причем без необходимости реализовывать новые функции.\n\nОбсудим рассмотренные ранее операции — отображение, фильтрация и агрегация. Комбинируясь друг с другом, они позволяют решать подавляющее число задач по обработке коллекций. С чем-то подобным мы все встречались в своей жизни, когда собирали конструкторы Lego. Небольшое число примитивных деталей за счет одинаковых соединений позволяет строить конструкции практически неограниченной сложности.\n\nКстати, подобные цепочки нередко заканчиваются на агрегации, потому что агрегация почти всегда выполняется в конце и сводит коллекцию к некоторому значению.\n\n## Производительность\n\nЗа кадром остался вопрос производительности. Возможно, вы догадались, что на каждый вызов функции, обрабатывающей коллекцию, мы получаем проход по всему списку. Чем больше таких функций, тем больше проходов. Казалось бы, код замедляется, зачем так делать? На практике дополнительные проходы практически никогда не проблема (см. ссылку \"Продуманная оптимизация\"). Задачи, в которых требуется одномоментная обработка десятков и сотен тысяч элементов, встречаются крайне редко. Большая часть операций происходит со списками до тысяч элементов. А для такого списка одним проходом больше, одним меньше — нет никакой разницы.\n\nНо это не вся правда. На самом деле, существуют специальные коллекции, которые в момент вызова функций фильтрации и отображения не выполняют операции сразу. Они накапливают необходимые действия, а во время первого использования выполняют сразу все одним проходом. Это так называемые **ленивые коллекции**.\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":2280,"name":"theory","url":"/courses/php-functions/lessons/about/theory_unit"}],"links":[],"ordered_units":[{"id":2280,"name":"theory","url":"/courses/php-functions/lessons/about/theory_unit"}],"id":1086,"slug":"about","state":"approved","name":"Введение","course_order":1,"goal":"Знакомимся с курсом, его структурой, задачами и целями","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Функции – это мощный инструмент с широкими возможностями. Ранее в курсах профессии «PHP-программист» мы сталкивались только с именованными функциями, они самые простые. Кроме них, в PHP есть анонимные функции, которые заметно расширяют выразительные возможности языка. Они используются как в простых задачах при обработке коллекций, так и в современных веб-фреймворках при создании сайтов.\n\nЭтот курс поможет разобраться с функциями по-настоящему. Все, что было ранее — это всего лишь верхушка айсберга. Мы рассмотрим самые полезные функции, которых нет в PHP, но есть в сторонних библиотеках. Вы научитесь использовать некоторые из этих библиотек, что пригодится в дальнейших курсах. Мы изучим новый подход к обработке коллекций и выйдем на другой уровень понимания.\n\nВ этом курсе вы изучите:\n\n* Детерминированность\n* Побочные эффекты\n* Оператор Spread\n* Объекты первого рода\n* Функции высшего порядка (`map`, `filter` и `reduce`)\n* Функциональное программирование\n\nНе все из перечисленных тем и возможностей используются в повседневной жизни PHP-разработчика, но знать о них нужно по двум причинам:\n\n* Все эти подходы не специфичны для PHP. Зная их, вы сможете гораздо легче переключаться на другие языки\n* Работа с функциями сильно прокачивает общий уровень разработчика\n"},"id":162,"slug":"php-functions","challenges_count":11,"name":"PHP: Функции","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы изучите функции. Вы узнаете, что такое объекты первого рода, безымянные лямбда-функции и функции высшего порядка. Вы научитесь использовать функции внутри других функций, использовать встроенные операции map, filter, reduce и писать обертки для расширения функциональности. Знания из этого курса помогут проектировать лаконичные и эффективные программы, отделять побочные эффекты от чистого кода.","kind":"additional","updated_at":"2026-01-20T11:42:10.422Z","language":"php","duration_cache":68940,"skills":["Писать лаконичный и эффективный код с помощью продвинутых возможностей функций","Отделять чистые функции от функций с побочными эффектами","Использовать функции высшего порядка для обработки коллекций (map/filter/reduce)","Отличать императивную парадигму программирования от декларативной (функциональной)"],"keywords":["упаковка и распаковка","функции высшего порядка","замыкания","чистые функции"],"lessons_count":17,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjUyMSwicHVyIjoiYmxvYl9pZCJ9fQ==--8faac8ed24114d5b99337cfb662226b5fcf61425/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJwbmciLCJyZXNpemVfdG9fZmlsbCI6WzYwMCw0MDBdfSwicHVyIjoidmFyaWF0aW9uIn19--6067466c2912ca31a17eddee04b8cf2a38c6ad17/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-functions/lessons/signals/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>Пример с <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">usort()</code> хорошо демонстрирует важность и удобство функций высшего порядка для решения повседневных задач. Описав алгоритм один раз, мы можем получать различные варианты поведения, специфицируя их функциями. То же самое относится к рассмотренным функциям <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">map()</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">filter()</code> и <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">reduce()</code>. Но есть еще один важный аспект, который требует рассмотрения.</p>
<p>Типичный код на PHP выглядит так: программа делает один цикл, внутри которого выполняются сразу все операции. В конце получается некоторый интересующий нас результат. Ничего криминального, но такой код сложно анализировать, потому что приходится держать в голове сразу все операции. С другой стороны, при использовании функций высшего порядка принято разделять задачу на подзадачи и выполнять их последовательно друг за другом, выстраивая в цепочку операций.</p>
<p>В <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://guides.hexlet.io/ru/how-to-learn-sicp/" rel="noopener noreferrer" target="_blank">СИКП</a> такой подход сравнивают с тем, как происходит <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%81%D0%B8%D0%B3%D0%BD%D0%B0%D0%BB%D0%BE%D0%B2" rel="noopener noreferrer" target="_blank">обработка сигналов</a> при проектировании электросхем. Ток, протекая по схеме, проходит через цепочку преобразователей: фильтров, подавителей шума, усилителей и так далее. Напряжение (и создаваемый им ток) в этом случае выполняет роль данных, а преобразователи – роль функций.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjU0NSwicHVyIjoiYmxvYl9pZCJ9fQ==--4398aae763c2e51c5a8d4642808f444083adf4aa/convertor.png" alt="Обработка сигналов" loading="lazy"/></p>
<p>Представим функцию, которая принимает на вход список путей файловой системы, находит среди них файлы с расширением <em>.php</em> без учета регистра и возвращает имена этих файлов. Для решения этой задачи понадобятся следующие функции:</p>
<ul>
<li><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">is_file()</code> проверяет, что переданный путь — это реально существующий файл</li>
<li><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">pathinfo()</code> позволяет извлекать расширение из имени файла</li>
<li><code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">basename()</code> извлекает имя файла из полного пути</li>
</ul>
<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
function getPHPFileNames(array $paths)
{
$result = [];
foreach ($paths as $path) {
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
if (is_file($path) && $extension === 'php') {
$result[] = basename($path);
}
}
return $result;
}
$names = getPHPFileNames(['index.php', 'wop.PHP', 'nonexists', 'node_modules']);
print_r($names);
// => Array
// (
// [0] => index.php
// [1] => wop.PHP
// )</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>
<ol>
<li>Просматриваем каждый путь</li>
<li>Если текущий путь — файл с расширением <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">php</code> (без учета регистра), то добавляем его имя в результирующий массив</li>
</ol>
<p>Если попытаться то же самое реализовать через функцию <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">array_reduce()</code>, то на выходе получится код, идентичный решению на циклах. Но если хорошо подумать, то эта задача распадается на две — фильтрацию и отображение:</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
function getPHPFileNames(array $paths)
{
// Фильтруем, оставляя только подходящие пути
$phpFiles = array_filter($paths, function ($path) {
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
return is_file($path) && $extension === 'php';
});
// Извлекаем имена файлов из оставшихся путей и возвращаем их наружу
return array_map(fn($path) => basename($path), $phpFiles);
}
$names = getPHPFileNames(['index.php', 'wop.PHP', 'nonexists', 'node_modules']);
print_r($names);
// => Array
// (
// [0] => index.php
// [1] => wop.PHP
// )</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>Код получился чуть короче, но и многословнее — это исключительно особенность PHP. Тем не менее здесь размер не принципиален. С увеличением количества операций и их сложности такой код читается и анализируется значительно проще, потому что каждая операция выполняется независимо для всего набора сразу. В голове приходится держать меньше деталей, можно сразу увидеть то, как операция влияет на все данные. Но научиться правильно разбивать задачу на подзадачи не так просто, как может показаться. Нужна некоторая практика и сноровка перед тем, как ваш код станет удобоваримым.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="/rails/active_storage/blobs/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NjU0NiwicHVyIjoiYmxvYl9pZCJ9fQ==--289c5e6969e1555488fe0d7f43dfe8a90ff6b757/legos.jpg" alt="Standard Interfaces" loading="lazy"/></p>
<p>Сама возможность такого разбиения основывается на простой идее, которую иногда называют <strong>стандартные интерфейсы</strong>. Эта идея заключается в том, что на входе и выходе из функций ожидается один и тот же тип данных в нашем случае, это массив. Это позволяет соединять функции и строить цепочки, выполняющие большое количество разных задач, причем без необходимости реализовывать новые функции.</p>
<p>Обсудим рассмотренные ранее операции — отображение, фильтрация и агрегация. Комбинируясь друг с другом, они позволяют решать подавляющее число задач по обработке коллекций. С чем-то подобным мы все встречались в своей жизни, когда собирали конструкторы Lego. Небольшое число примитивных деталей за счет одинаковых соединений позволяет строить конструкции практически неограниченной сложности.</p>
<p>Кстати, подобные цепочки нередко заканчиваются на агрегации, потому что агрегация почти всегда выполняется в конце и сводит коллекцию к некоторому значению.</p>
<h2 id="heading-2-1">Производительность</h2>
<p>За кадром остался вопрос производительности. Возможно, вы догадались, что на каждый вызов функции, обрабатывающей коллекцию, мы получаем проход по всему списку. Чем больше таких функций, тем больше проходов. Казалось бы, код замедляется, зачем так делать? На практике дополнительные проходы практически никогда не проблема (см. ссылку "Продуманная оптимизация"). Задачи, в которых требуется одномоментная обработка десятков и сотен тысяч элементов, встречаются крайне редко. Большая часть операций происходит со списками до тысяч элементов. А для такого списка одним проходом больше, одним меньше — нет никакой разницы.</p>
<p>Но это не вся правда. На самом деле, существуют специальные коллекции, которые в момент вызова функций фильтрации и отображения не выполняют операции сразу. Они накапливают необходимые действия, а во время первого использования выполняют сразу все одним проходом. Это так называемые <strong>ленивые коллекции</strong>.</p></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-functions/lessons/signals/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 / 17</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-functions/lessons/signals/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>