<!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:46:31 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="7sZGgtWmdPzaaSsa0zKjY4iIJ2Fd6V_pHzJgHPTJ-1UBF421J9jZnGwqD4LfPVMUSIEKy1XeoUui0vpIps4cOw";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-introduction-to-oop/lessons/interfaces/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-introduction-to-oop/lessons/interfaces/theory_unit">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="Z8uHi4XF4a767Zv0C6RCTI8pUd6r_WxD-xz7tC2dK8aIGky8d7tMzkyuv2wHq7I7TyB8dKPKkuFG_GHgf5rMqA" />
<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="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1MSwicHVyIjoiYmxvYl9pZCJ9fQ==--e5793a1818ff43d73135cc7ed88c1998d7650470/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Developer%20activity-bro.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NTIxNSwicHVyIjoiYmxvYl9pZCJ9fQ==--ee06f514098550b5ac7eebce6227b1543399a37c/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Hand%20coding-rafiki.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:46:31.080Z","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":"JwjUHVETPHuCypweMh_SuPwiqcmEzBepfAtiyGHqbf7I2R8qo22RGzSJuIY-ECLPPCuEY4z76QvB6_icM-2KkA","topics":[{"id":27251,"title":"А это нормально что такой код проходит тесты?\n```\ninterface Comparable\n{\n \n}\n```","plain_title":"А это нормально что такой код проходит тесты? ``` interface Comparable { } ``` ","creator":{"public_name":"Anatoly Abrekov","id":126683,"is_tutor":false},"comments":[{"creator":{"public_name":"Andy","id":117329,"is_tutor":false},"id":60723,"body":"Можно тесты добавить:\n\n```\n$interfaceName = 'App\\Comparable';\n$reflectionUser = new \\ReflectionClass('App\\User');\n\n$this->assertTrue($reflectionUser->implementsInterface($interfaceName));\n\n\n$reflectionComparable = new \\ReflectionClass($interfaceName);\n\n$this->assertTrue($reflectionComparable->hasMethod('compareTo'));\n```","topic_id":27251},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":58550,"body":"Тесты не проверяют внутренности, они смотрят только на поведение. А при таком интерфейсе с поведением все нормально. По хорошему, PHP должен ругаться на подобный интерфейс, но он этого не делает.","topic_id":27251},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":60824,"body":"Ага, но пока это наша внутренняя позиция. Не затачиваться на такие проверки. ","topic_id":27251},{"creator":{"public_name":"Andy","id":117329,"is_tutor":false},"id":60826,"body":"Мне просто интересно стало, как будут наличие интерфейса проверять - и сразу в тесты полез (обычно в процессе написания кода лезу, а не до). А там и нет ничего такого - предоставился отличный шанс для меня потыкать палочкой в рефлексию. ","topic_id":27251},{"creator":{"public_name":"Vyacheslav","id":104400,"is_tutor":false},"id":68325,"body":"https://prnt.sc/p0ehyu\nhttps://prnt.sc/p0eimp\nМожно было назвать файл для интерфейса соответствующим образом.\nmv выручает)","topic_id":27251}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":48531,"title":"Не должны ли мы описывать все методы имплементирующего класса в интерфейсе? В решении учителя только один. [Моё ревью](https://ru.hexlet.io/code_reviews/328837)","plain_title":"Не должны ли мы описывать все методы имплементирующего класса в интерфейсе? В решении учителя только один. Моё ревью (https://ru.hexlet.io/code_reviews/328837) ","creator":{"public_name":"Валерий Серёгин","id":174277,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":104242,"body":"Приветствую, Валерий!\n\nВладмир всё правильно сказал. Об этом говорится в теории к уроку:\n\n> Реализация интерфейса никак не ограничивает возможности по наполнению класса, другими словами, вы можете определять и добавлять в класс все, что хотите, помимо интерфейсных функций.\n\nЕсли вам помог ответ Владимира, то можете нажать на кнопку \"Отметить как решение\" и таким образом поблагодарить его за помощь.","topic_id":48531},{"creator":{"public_name":"Vladimir Minkin","id":248254,"is_tutor":false},"id":104183,"body":"**Валерий Серёгин**, класс должен реализовать все методы, описанные в интерфейсе, иначе произойдет фатальная ошибка, однако класс может иметь свои собственные методы, не описанные в интерфейсе, тем самым расширяя функционал.","topic_id":48531}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":17972,"title":"\n\n> class DecartPoint implements DecartPointInterface\n> {\n> private $x;\n> private $y;\n> \n> // Интерфейсные функции\n> \n> public function __construct($x, $y)\n> {\n> $this->x = $x;\n> $this->y = $y;\n> }\n> \n> public getX()\n> {\n> return $this->x;\n> }\n> \n> public getY()\n> {\n> return $this->y;\n> }\n\n в тексте public без function ?","plain_title":" class DecartPoint implements DecartPointInterface { private $x; private $y; // Интерфейсные функции public function __construct($x, $y) { $this->x = $x; $this->y = $y; } public getX() { return $this->x; } public getY() { return $this->y; } в тексте public без function ? ","creator":{"public_name":"Zsuravljov Georgij","id":183433,"is_tutor":false},"comments":[{"creator":{"public_name":"Александр О.","id":61806,"is_tutor":false},"id":37985,"body":"Опечатка - поправил, спасибо!","topic_id":17972}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":43699,"title":"Попробывал поэкспериментировать с примером из теории на repl. \nЕсли удалить реализацию инерфейса Countable , то ответ почему- то меняется с 3 на 1..пока не могу понять почему, ведь реализация метода count не поменялась\n\n```\nclass Collection \n{\n private $items;\n \n public function __construct($items = [])\n {\n $this->items = $items;\n }\n \n public function count()\n {\n return sizeof($this->items);\n }\n}\n\n$coll = new Collection([3, 2, 5]);\nprint_r(count($coll)); //1\n```","plain_title":"Попробывал поэкспериментировать с примером из теории на repl. Если удалить реализацию инерфейса Countable , то ответ почему- то меняется с 3 на 1..пока не могу понять почему, ведь реализация метода count не поменялась class Collection { private $items; public function __construct($items = []) { $this->items = $items; } public function count() { return sizeof($this->items); } } $coll = new Collection([3, 2, 5]); print_r(count($coll)); //1 ","creator":{"public_name":"Виталий Кудрявцев","id":128341,"is_tutor":false},"comments":[{"creator":{"public_name":"Виталий Кудрявцев","id":128341,"is_tutor":false},"id":95031,"body":"\nПонял, спасибо! получается нельзя как написано в теории удалить в объявлении класса имплементации и ничего не поломать ?","topic_id":43699},{"creator":{"public_name":"Nikolai Gagarinov","id":104929,"is_tutor":true},"id":95033,"body":"Виталий, если код завязан на стандартные интерфейсы PHP, то это может вызвать ошибки (как мы увидели выше).\nРечь идет о пользовательских интерфейсах. Потому что если в классе (объекте) метод есть, который требуется в интерфейсе, то он никуда не денется (просто при попытке вызыва будет ошибка).","topic_id":43699},{"creator":{"public_name":"Nikolai Gagarinov","id":104929,"is_tutor":true},"id":94953,"body":"Привет, если мы не реализуем интерфейс Countable, то метод count не будет вызываться. По сути будет подсчет объекта (одна штука), а не коллекции.","topic_id":43699},{"creator":{"public_name":"Виталий Кудрявцев","id":128341,"is_tutor":false},"id":95037,"body":"**Nikolai Gagarinov**, Николай, спасибо !","topic_id":43699},{"creator":{"public_name":"Stanislav Dzisiak","id":212236,"is_tutor":true},"id":95025,"body":"Приветствую, Виталий!\n\nНиколай верно подсказывает, для того что бы был вызван метод count() нужно чтобы класс реализовывал интерфейс Countable. В ином случае вызов функции count() будет возвращать единицу, за исключением случая если в функцию передать null, тогда будет возвращен 0. Подробнее об этом можно посмотреть на странице документации по функции [count()](https://www.php.net/manual/ru/function.count.php).","topic_id":43699}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":48399,"title":"я уже второе задание делаю чисто по образцу, вообще не понятно зачем этот интерфейс и в чем его практическая польза...надеюсь, дальше будет понятнее или я совсем запутаюсь((","plain_title":"я уже второе задание делаю чисто по образцу, вообще не понятно зачем этот интерфейс и в чем его практическая польза...надеюсь, дальше будет понятнее или я совсем запутаюсь(( ","creator":{"public_name":"Динара Хажипова","id":312372,"is_tutor":false},"comments":[{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":104031,"body":"Приветствую, Динара!\n\nСейчас самое главное, это запомнить, что интефейсы обязывают классы реализовывать методы которые в них описаны. Интерфейсы описывают названия и сигнатуры (параметры) методов для классов. Когда код выполняется, интерпретатор проводит проверку на то реализует ли класс соответствующий интерфейс. Если какие-то методы отсутствуют в классе, то возникает ошибка. А вот когда нужно использовать интерфейс это уже зависит от конкретной ситуации и понимание этого момента придёт с опытом и практикой.","topic_id":48399}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":43518,"title":"Так всё-таки, как правильнее делать в сигнатуре функций? \n`function compare(DecartPointInterface $point1, DecartPointInterface $point2)` \nили \n`function compare(DecartPoint $point1, DecartPoint $point2)`\n\nНасколько допустимы оба варианта? ","plain_title":"Так всё-таки, как правильнее делать в сигнатуре функций? function compare(DecartPointInterface $point1, DecartPointInterface $point2) или function compare(DecartPoint $point1, DecartPoint $point2) Насколько допустимы оба варианта? ","creator":{"public_name":"Denis Skvortsov","id":185650,"is_tutor":false},"comments":[{"creator":{"public_name":"Denis Skvortsov","id":185650,"is_tutor":false},"id":94704,"body":"> Если интерфейса нет, то лучше и не добавлять до тех пор пока не понадобится.\n\nА когда он может понадобится? То есть, вот мы здесь изучили, что есть такая штука вообще, что есть такой синтаксис, но до сих пор непонятно, **для чего** они нужны.\n\nВот из теории:\n> Например, можно в любой программе открыть все файлы с классами и удалить часть определения класса, которая описывает реализацию интерфейсов (слово implements и то, что идёт за ним). После этого не изменится ровным счётом ничего — программа продолжит выполняться так же, как и выполнялась. Но ситуация меняется, если использовать интерфейс в сигнатурах функций и методов вместо классов.\n\nВыпилим интерфейсы - ничего не сломается. Если интерфейс в сигнатурах функций, то сломается. Но, оказывается, не везде в сигнатурах стоит использовать интерфейсы, можно (и иногда лучше) и без них. \nКороче, как-то не до полной ясности раскрыта тема, как по мне (никогда до этого не сталкивался с интерфейсами и пытаюсь разобраться). \n","topic_id":43518},{"creator":{"public_name":"Denis Skvortsov","id":185650,"is_tutor":false},"id":94723,"body":"**Nikolai Gagarinov**, \n> логгер, http клиент, http сообщения (запрос ответ)\n\nПока фиг знает, что это :) Но понимаю так, что есть какие-то вещи, к которым принято (положено) делать интерфейсы для замены \"внутренностей\" без каких-либо изменений со стороны принимающей стороны.","topic_id":43518},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":94686,"body":"Угу, все верно. В теории говорят завязывайтесь всегда на интерфейсы, но делать интерфейсы на каждый чих это не очень. Кода станет очень много, а заменяться он практически никогда не будет. Если интерфейса нет, то лучше и не добавлять до тех пор пока не понадобится.","topic_id":43518},{"creator":{"public_name":"Nikolai Gagarinov","id":104929,"is_tutor":true},"id":94713,"body":"https://www.php-fig.org/psr/ Описывает некоторые общие интерфейсы для компонентов, например логгер, http клиент, http сообщения (запрос ответ). \nЭто сделано для того, чтобы можно было одну библиотеку подменить на другую без проблем.\nТ.е. как раз тот случай, когда завязываемся на интерфейс, а не реализацию.","topic_id":43518},{"creator":{"public_name":"Nikolai Gagarinov","id":104929,"is_tutor":true},"id":94573,"body":"Привет, оба варианта допустимы. Уже зависит от конкретного кода.\nЗавязываться на интерфейс полезно, когда у нас нам например нужна библиотека - например интерфейсы PSR-7, логгер или Http клиент.\nТ.е. там, где мы хотим подменить реализацию (например что-то протестировать или использовать полиморфизм (например Пользователь и Гость).\nНо делать все через интерфейсы (как рекомендуют некоторые) не всегда хорошая практика, чаще приводит к раздуванию кода.\nПонимание что как и когда приходит с опытом.","topic_id":43518}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":59070,"title":"Добрый день.\nПрочитал обсуждения ниже, присоединюсь к тем, кто тоже не понял для чего используется интерфейс.\nНе понятно, если все работает без интерфейса каковы случае, когда его таки необходимо применять?","plain_title":"Добрый день. Прочитал обсуждения ниже, присоединюсь к тем, кто тоже не понял для чего используется интерфейс. Не понятно, если все работает без интерфейса каковы случае, когда его таки необходимо применять? ","creator":{"public_name":"Виктор Григорьев","id":256695,"is_tutor":false},"comments":[{"creator":{"public_name":"Виктор Григорьев","id":256695,"is_tutor":false},"id":125027,"body":"Ясно","topic_id":59070},{"creator":{"public_name":"Roman Ashikov","id":226258,"is_tutor":true},"id":124943,"body":"Приветствую, Виктор!\n\nТак ведь говорится о случае, когда интерфейс уже реализован. Если его убрать, то всё продолжит работать как ни в чём не бывало. \n\n> Интерпретатор проверяет, чтобы в классе были описаны все функции интерфейса и их сигнатуры совпадали, а если это не так, то возникает ошибка.\n\nА вот тут как раз говорится о том, что если мы пишем класс, который реализует какой-то описанный интерфейс и забываем имплементировать какой-то метод, то будет выдана ошибка. Забегая вперёд скажу, что интерфейсы активно используются для полиморфизма — [полиморфизм подтипов](https://ru.hexlet.io/courses/php-polymorphism/lessons/subtyping-polymorphism/theory_unit).","topic_id":59070}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":28496,"title":"Мммм, про интерфейсы написано, а про абстрактные классы что-то не помню чтобы было, и судя по заголовкам уроков в этом и последующих курсах про абстрактные классы ничего нету, по крайней мере урока. Странно как-то, не помешало бы. Особенно про разницу с интерфейсами подробнее.","plain_title":"Мммм, про интерфейсы написано, а про абстрактные классы что-то не помню чтобы было, и судя по заголовкам уроков в этом и последующих курсах про абстрактные классы ничего нету, по крайней мере урока. Странно как-то, не помешало бы. Особенно про разницу с интерфейсами подробнее. ","creator":{"public_name":"Bator Zhigzhitov","id":186940,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":61418,"body":"Абстрактные классы это не основа ооп, более того, они сами по себе всего лишь припарка сбоку. Про абстрактные классы (и наследование) будет рассказываться в курсе, которые прямо сейчас пишется: https://ru.hexlet.io/courses/php-classes","topic_id":28496},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":61424,"body":"Там еще по полиморфизму курс","topic_id":28496},{"creator":{"public_name":"Bator Zhigzhitov","id":186940,"is_tutor":false},"id":61426,"body":"Я их 6 штук насчитал, новых, тех что у меня нету изначально.","topic_id":28496},{"creator":{"public_name":"Bator Zhigzhitov","id":186940,"is_tutor":false},"id":61423,"body":"О, горка новых курсов, пройдём :D","topic_id":28496}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":25490,"title":"Не могу понять для чего нужны интерфейсы. Зачем классу реализовывать интерфейс, что это дает? Ведь можно просто создать класс с таким же поведением как в интерфейсе. Выглядит как бесполезный код, который ничего не делает. Читал много где про них, но саму идею не понимаю.\n\nПример интерфейса из урока.\n```\ninterface DecartPointInterface\n{\n public function __construct($x, $y);\n public function getX();\n public function getY();\n}\n```\nПредположим мы реализуем на его основе класс. Какую пользу мы получим? Отделение описания методов от реализации? Допустим, но что это дает? Как я вижу, это описание не дает ничего кроме возможности наследоваться от нескольких интерфейсов, что мне кажется тоже мало полезным. Зачем отделять описание от реализации, в описании же все равно ничего не понятно, только названия функций. Можно создать точно такой же класс как тот что будет наследовать интерфейс, но только без интерфейса. Что изменится? Мне кажется что ничего.\n\nПосоветуйте пожалуйста что нибудь чтобы понять интерфейсы, и вообще все это ООП. Может я тупой, не знаю, почему то не могу понять ООП ни в какую.","plain_title":"Не могу понять для чего нужны интерфейсы. Зачем классу реализовывать интерфейс, что это дает? Ведь можно просто создать класс с таким же поведением как в интерфейсе. Выглядит как бесполезный код, который ничего не делает. Читал много где про них, но саму идею не понимаю. Пример интерфейса из урока. interface DecartPointInterface { public function __construct($x, $y); public function getX(); public function getY(); } Предположим мы реализуем на его основе класс. Какую пользу мы получим? Отделение описания методов от реализации? Допустим, но что это дает? Как я вижу, это описание не дает ничего кроме возможности наследоваться от нескольких интерфейсов, что мне кажется тоже мало полезным. Зачем отделять описание от реализации, в описании же все равно ничего не понятно, только названия функций. Можно создать точно такой же класс как тот что будет наследовать интерфейс, но только без интерфейса. Что изменится? Мне кажется что ничего. Посоветуйте пожалуйста что нибудь чтобы понять интерфейсы, и вообще все это ООП. Может я тупой, не знаю, почему то не могу понять ООП ни в какую. ","creator":{"public_name":"","id":82584,"is_tutor":false},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":54536,"body":"По плану будет третий курс по ооп, где раскроется этот смысл.\n\nВ двух словах, без интерфейса можно жить если язык поддерживает утиную типизацию, что собственно и происходит в ruby, js или python. PHP тоже поддерживает утиную типизацию, но в нем принята модель Java, поэтому он такой. Чисто технически интерфейсы используются как указание типа в аргументах функции `(MySuperInterface $var)`, таким образом специфицируется ожидаемое поведение. На это можно возразить, что туда можно подставить имя класса. Да можно, но тогда станет невозможным полиморфизм (таким каким он должен быть). Про полиморфизм будет позже.","topic_id":25490},{"creator":{"public_name":"","id":82584,"is_tutor":false},"id":54570,"body":"Спасибо. Может вы знаете что почитать для понимания, книги или статьи?","topic_id":25490},{"creator":{"public_name":"","id":82584,"is_tutor":false},"id":54696,"body":"Огромное спасибо","topic_id":25490},{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":54585,"body":"Конкретное не посоветую, но попробуйте разобраться с понятием \"полиморфизм\"","topic_id":25490}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}},{"id":16118,"title":"Мне кажется, этот урок нужно немного упростить и расширить. Из текущего текста, даже имея представления об интерфейсах, мало что понятно. Можно описать, что интерфейсы хранят, условно говоря, названия функций, которые должны быть реализованы в классе, имплементирующем данный интерфейс `*` . Добавить, что интерфейсы могут хранить константы (зачем - не знаю). Ещё можно упомянуть абстрактный класс, как альтернативу интерфейсу и о преимуществах одного над другим.\n\n`*` классический пример:\n```\nИнтерфейс \"Figure\", содержащий метод `getArea` и классы `Triangle`, `Circle`, `Rectangle`, имплементирующие данный интерфейс и реализующие указанный метод.\n```","plain_title":"Мне кажется, этот урок нужно немного упростить и расширить. Из текущего текста, даже имея представления об интерфейсах, мало что понятно. Можно описать, что интерфейсы хранят, условно говоря, названия функций, которые должны быть реализованы в классе, имплементирующем данный интерфейс * . Добавить, что интерфейсы могут хранить константы (зачем - не знаю). Ещё можно упомянуть абстрактный класс, как альтернативу интерфейсу и о преимуществах одного над другим. * классический пример: Интерфейс \"Figure\", содержащий метод `getArea` и классы `Triangle`, `Circle`, `Rectangle`, имплементирующие данный интерфейс и реализующие указанный метод. ","creator":{"public_name":"Sergei Melodyn","id":162475,"is_tutor":true},"comments":[{"creator":{"public_name":"Kirill Mokevnin","id":1,"is_tutor":false},"id":34228,"body":"Обновил.","topic_id":16118}],"communitable":{"parent_entity_name":null,"parent_entity_url":null,"entity_name":"Интерфейсы","entity_url":null,"active":true}}],"lesson":{"exercise":{"id":743,"slug":"php_introduction_to_oop_interfaces_exercise","name":null,"state":"active","kind":"exercise","language":"php","locale":"ru","has_web_view":false,"has_test_view":false,"reviewable":true,"readme":"## src\\User.php\n\nРеализуйте класс `User`, который создает пользователей. Конструктор класса принимает на вход два параметра: идентификатор и имя.\n\nРеализуйте интерфейс `ComparableInterface` для класса `User`. Сравнение пользователей происходит на основе их идентификатора.\n\n```php\n<?php\n\n$user1 = new User(4, 'tolya');\n$user2 = new User(1, 'petya');\n\n$user1->compareTo($user2); // false\n```\n","prepared_readme":"## src\\User.php\n\nРеализуйте класс `User`, который создает пользователей. Конструктор класса принимает на вход два параметра: идентификатор и имя.\n\nРеализуйте интерфейс `ComparableInterface` для класса `User`. Сравнение пользователей происходит на основе их идентификатора.\n\n```php\n<?php\n\n$user1 = new User(4, 'tolya');\n$user2 = new User(1, 'petya');\n\n$user1->compareTo($user2); // false\n```\n","has_solution":true,"entity_name":"Интерфейсы"},"units":[{"id":2380,"name":"theory","url":"/courses/php-introduction-to-oop/lessons/interfaces/theory_unit"},{"id":2578,"name":"quiz","url":"/courses/php-introduction-to-oop/lessons/interfaces/quiz_unit"},{"id":2381,"name":"exercise","url":"/courses/php-introduction-to-oop/lessons/interfaces/exercise_unit"}],"links":[{"id":424947,"name":"Официальная документация","url":"https://php.net/manual/ru/language.oop5.interfaces.php"},{"id":424948,"name":"Отделенный интерфейс","url":"https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D1%80%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81%D0%B0"},{"id":424949,"name":"Абстрактный тип данных","url":"https://ru.wikipedia.org/wiki/Абстрактный_тип_данных"}],"ordered_units":[{"id":2380,"name":"theory","url":"/courses/php-introduction-to-oop/lessons/interfaces/theory_unit"},{"id":2578,"name":"quiz","url":"/courses/php-introduction-to-oop/lessons/interfaces/quiz_unit"},{"id":2381,"name":"exercise","url":"/courses/php-introduction-to-oop/lessons/interfaces/exercise_unit"}],"id":1138,"slug":"interfaces","state":"approved","name":"Интерфейсы","course_order":898,"goal":"Знакомимся с новой конструкцией для создания явных интерфейсов","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Вместе с классами в PHP широко используется языковая конструкция \"интерфейс\". В этом уроке мы рассмотрим техническую сторону вопроса, а потом поговорим о смысле. Про последнее я сейчас могу сказать немного, потому что полноценный разговор про суть интерфейсов у нас пойдёт во время изучения полиморфизма в последующих курсах. А пока достаточно иметь общее представление об интерфейсах, так как без них не получится окунуться во фреймворки.\n\nИнтерфейс в PHP — конструкция языка, описывающая [абстрактный тип данных](https://ru.wikipedia.org/wiki/Абстрактный_тип_данных) (АТД). Напомню, что АТД определяет набор операций (функций), независимых от конкретной реализации типа (в нашем случае класса) для манипулирования его значениями. На практике интерфейсы содержат определения функций (то есть описание их сигнатур) без реализации.\n\nХотя данная конструкция для нас в новинку, само понятие интерфейса используется на протяжении всего курса. В первую очередь это рассуждения о типах. Для оперирования точками на плоскости нам не нужна \"реализация\" точек. Достаточно того, что мы представляем их визуально и знаем операции, выполняемые над ними. То же самое касается и более базовых концепций, например, чисел и любых арифметических операций. Задумывались ли вы над тем, как на самом деле выполняются арифметические операции? Ответ на этот вопрос гораздо сложнее, чем может показаться на первый взгляд, и он зависит не только от языка, но и от конкретного аппаратного обеспечения (железа). Однако незнание ответа не мешает нам пользоваться числами, строками и массивами, не зная их устройства.\n\n```php\n<?php\n\n// file: DecartPointInterface.php\n\nnamespace App;\n\n// Интерфейсы, по аналогии с классами, хранятся в своих собственных файлах\n// и загружаются автоматически при следовании стандарту PSR-4.\n\n// Имя интерфейса может быть любым, главное — соответствие PSR-4.\ninterface DecartPointInterface\n{\n public function __construct($x, $y);\n public function getX();\n public function getY();\n}\n```\n\nТо, что раньше мы описывали словами и держали в голове, теперь явно записано в виде кода. Декартова точка — это АТД с тремя операциями:\n\n* Создание точки из двух значений\n* Извлечение координаты X\n* Извлечение координаты Y\n\nПо сути, прикладному коду больше ничего знать о точках и не нужно. Естественно, если нам понадобятся новые операции, то мы всегда можем их добавить, тем самым расширив интерфейс. Свои собственные АТД можно менять как угодно и когда угодно, только учтите, что изменение интерфейса обычно приводит к необходимости править код, использующий его.\n\nСама по себе конструкция `Interface` никак не влияет на остальной код. Недостаточно просто создать интерфейс, в этом нет смысла. Интерфейс должен быть *реализован*, и тогда он начнёт приносить пользу.\n\n```php\n<?php\n\nnamespace AnotherApp;\n\n// Импорт интерфейса\nuse App\\DecartPointInterface;\n\nclass DecartPoint implements DecartPointInterface\n{\n private $x;\n private $y;\n\n // Интерфейсные функции\n\n public function __construct($x, $y)\n {\n $this->x = $x;\n $this->y = $y;\n }\n\n public function getX()\n {\n return $this->x;\n }\n\n public function getY()\n {\n return $this->y;\n }\n\n // Не интерфейсные функции\n\n public function __toString()\n {\n return \"({$this->getX()}, {$this->getY()})\";\n }\n}\n```\n\nРеализация интерфейса происходит за счёт ключевого слова `implements`, за которым идёт название интерфейса. Интерпретатор проверяет, чтобы в классе были описаны все функции интерфейса и их сигнатуры совпадали, а если это не так, то возникает ошибка. Реализация интерфейса никак не ограничивает возможности по наполнению класса, другими словами, вы можете определять и добавлять в класс все, что хотите, помимо интерфейсных функций.\n\nНасколько наличие интерфейсов критично для PHP программ? Например, можно в любой программе открыть все файлы с классами и удалить часть определения класса, которая описывает реализацию интерфейсов (слово `implements` и то, что идёт за ним). После этого не изменится ровным счётом ничего — программа продолжит выполняться так же, как и выполнялась. Но ситуация меняется, если использовать интерфейс в сигнатурах функций и методов вместо классов.\n\n```php\n<?php\n\nfunction compare(DecartPointInterface $point1, DecartPointInterface $point2)\n{\n // ...\n}\n```\n\nВо время выполнения программы PHP проверяет, реализует ли класс соответствующий интерфейс, и если нет, то возникает ошибка. Причём проверка идёт именно на наличие записи `implements` в определении класса, а не на факт того, что методы определены (проверка реализации интерфейса гарантирует это).\n\nТакая запись позволяет коду завязываться не на конкретную реализацию точек, а на их интерфейс. Это — ключевая мысль, которую имеет смысл обсуждать подробнее вместе с полиморфизмом.\n\nОтдельно стоит сказать, что один класс может реализовывать любое число интерфейсов, в таком случае они описываются через запятую:\n\n```php\n<?php\n\n// Пример из библиотеки DS, внутри которой реализованы различные структуры данных в объектном синтаксисе\n// https://github.com/php-ds/polyfill/blob/master/src/Stack.php\nclass Stack implements \\IteratorAggregate, \\ArrayAccess, Collection\n{\n // some code\n}\n```\n\nЗдесь класс *Stack* реализует сразу три интерфейса. Это значит, что внутри него должны быть реализованы методы всех указанных интерфейсов.\n\n*Если у разных интерфейсов окажутся методы с одинаковым названием, но разной сигнатурой, то возникнет ошибка. В таком случае придётся отказаться от одного из интерфейсов либо переделать их (например, переименовать методы)*\n\n## Интерфейс Countable\n\nВ PHP встроен интерфейс [Countable](https://php.net/manual/ru/class.countable.php), а функция `count` умеет работать с любым объектом, реализующим этот интерфейс.\n\n```php\n<?php\n\nclass Collection implements Countable\n{\n private $items;\n\n public function __construct($items = [])\n {\n $this->items = $items;\n }\n\n public function count()\n {\n return sizeof($this->items);\n }\n}\n\n$coll = new Collection([3, 2, 5]);\nprint_r(count($coll));\n// => 3\n```\n"},"lessonMember":null,"courseMember":null,"course":{"start_lesson":{"exercise":null,"units":[{"id":2333,"name":"theory","url":"/courses/php-introduction-to-oop/lessons/about/theory_unit"}],"links":[],"ordered_units":[{"id":2333,"name":"theory","url":"/courses/php-introduction-to-oop/lessons/about/theory_unit"}],"id":1110,"slug":"about","state":"approved","name":"О курсе","course_order":1,"goal":"Знакомимся с целями и задачами курса","self_study":null,"theory_video_provider":null,"theory_video_uid":null,"theory":"Этим курсом мы открываем цикл, посвящённый объектно-ориентированному программированию. Первый курс затрагивает самые основы, знакомит с базовым синтаксисом, концепциями и механизмом работы ООП в PHP. Следующие больше посвящены принципам написания программ в ООП-стиле, но и нового синтаксиса будет предостаточно.\n\nООП — большая тема, которой овладевают далеко не сразу. Пройдёт, возможно, не один год работы над реальными проектами, перед тем как картинка сложится.\n\nЭта часть курса содержит большое количество нового синтаксиса и терминов. Основные темы:\n\n* Объекты\n* Классы\n* Интерфейсы\n* Сокрытие данных (Data hiding)\n* Инкапсуляция\n* Автозагрузка\n* Исключения\n\nДанные темы крайне важны даже для начинающего PHP-разработчика потому, что с этими понятиями он начинает сталкиваться буквально с первых дней на новой работе. С другой стороны, требуется немало времени перед тем, как вы сможете действительно качественно использовать изучаемые подходы и техники в работе. К теме объектно-ориентированного программирования мы вернёмся в наших курсах ещё не раз и углубим не только наше понимание, но и разберём [оставшиеся понятия](https://php.net/manual/ru/language.oop5.php) вместе с их синтаксисом, например, абстрактные классы и трейты.\n"},"id":163,"slug":"php-introduction-to-oop","challenges_count":8,"name":"PHP: Введение в ООП","allow_indexing":true,"state":"approved","course_state":"finished","pricing_type":"paid","description":"На этом курсе вы познакомитесь с объектно ориентированным программированием на PHP. Вы узнаете о классах, интерфейсах, инкапсуляции и магических методах. В итоге поймете, для чего нужны классы как абстракция данных. Знание основ объектно ориентированного программирования пригодится, чтобы понимать плюсы и минусы кода с классами и объектами. Также это поможет использовать объекты для реализации программной логики.","kind":"basic","updated_at":"2026-01-20T11:51:04.565Z","language":"php","duration_cache":73500,"skills":["Описывать сущности предметной области с помощью классов","Использовать объекты для реализации программной логики","Подключать механизм автозагрузки классов (стандарт PSR4) в composer","Защищать состояние объектов от внешнего воздействия с помощью модификаторов доступа","Понимать плюсы и минусы кода с классами и объектами","Использовать исключения в своем коде"],"keywords":["классы","инкапсуляция","интерфейсы","исключения","автозагрузка","магические методы"],"lessons_count":18,"cover":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6ODMyNiwicHVyIjoiYmxvYl9pZCJ9fQ==--9a298bb6a7915cc9145958490291b3af909fc177/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"},{"stack":{"id":25,"slug":"php-oop","title":"ООП В PHP","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4300,"duration_in_months":2},"id":38,"slug":"php-oop","title":"ООП В PHP","subtitle":"Навык глубокого понимания архитектуры и написания чистого кода, позволяющий решать сложные задачи","subtitle_for_lists":"Изучите архитектуру и чистый код на PHP","locale":"ru","current":true,"duration_in_months_text":"2 месяца","stack_slug":"php-oop","price_text":"от 3 900 ₽","duration_text":"2 месяца","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1MSwicHVyIjoiYmxvYl9pZCJ9fQ==--e5793a1818ff43d73135cc7ed88c1998d7650470/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Developer%20activity-bro.png"},{"stack":{"id":468,"slug":"middle-php","title":"Middle-php разработчик","audience":"for_programmers","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"not_finished","order":2003,"duration_in_months":5},"id":596,"slug":"middle-php","title":"Middle-php разработчик","subtitle":"Освоите продвинутую работу с БД и серверной логикой","subtitle_for_lists":"Освоите продвинутую работу с БД и серверной логикой","locale":"ru","current":true,"duration_in_months_text":"5 месяцев","stack_slug":"middle-php","price_text":"от 4 050 ₽","duration_text":"5 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NTIxNSwicHVyIjoiYmxvYl9pZCJ9fQ==--ee06f514098550b5ac7eebce6227b1543399a37c/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Hand%20coding-rafiki.png"}],"lessonMemberUnit":null,"accessToLearnUnitExists":false,"accessToCourseExists":false},"url":"/courses/php-introduction-to-oop/lessons/interfaces/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>Вместе с классами в PHP широко используется языковая конструкция "интерфейс". В этом уроке мы рассмотрим техническую сторону вопроса, а потом поговорим о смысле. Про последнее я сейчас могу сказать немного, потому что полноценный разговор про суть интерфейсов у нас пойдёт во время изучения полиморфизма в последующих курсах. А пока достаточно иметь общее представление об интерфейсах, так как без них не получится окунуться во фреймворки.</p>
<p>Интерфейс в PHP — конструкция языка, описывающая <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%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D1%8B%D0%B9_%D1%82%D0%B8%D0%BF_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85" rel="noopener noreferrer" target="_blank">абстрактный тип данных</a> (АТД). Напомню, что АТД определяет набор операций (функций), независимых от конкретной реализации типа (в нашем случае класса) для манипулирования его значениями. На практике интерфейсы содержат определения функций (то есть описание их сигнатур) без реализации.</p>
<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
// file: DecartPointInterface.php
namespace App;
// Интерфейсы, по аналогии с классами, хранятся в своих собственных файлах
// и загружаются автоматически при следовании стандарту PSR-4.
// Имя интерфейса может быть любым, главное — соответствие PSR-4.
interface DecartPointInterface
{
public function __construct($x, $y);
public function getX();
public function getY();
}</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>
<ul>
<li>Создание точки из двух значений</li>
<li>Извлечение координаты X</li>
<li>Извлечение координаты Y</li>
</ul>
<p>По сути, прикладному коду больше ничего знать о точках и не нужно. Естественно, если нам понадобятся новые операции, то мы всегда можем их добавить, тем самым расширив интерфейс. Свои собственные АТД можно менять как угодно и когда угодно, только учтите, что изменение интерфейса обычно приводит к необходимости править код, использующий его.</p>
<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">Interface</code> никак не влияет на остальной код. Недостаточно просто создать интерфейс, в этом нет смысла. Интерфейс должен быть <em>реализован</em>, и тогда он начнёт приносить пользу.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code"><?php
namespace AnotherApp;
// Импорт интерфейса
use App\DecartPointInterface;
class DecartPoint implements DecartPointInterface
{
private $x;
private $y;
// Интерфейсные функции
public function __construct($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function getX()
{
return $this->x;
}
public function getY()
{
return $this->y;
}
// Не интерфейсные функции
public function __toString()
{
return "({$this->getX()}, {$this->getY()})";
}
}</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>Реализация интерфейса происходит за счёт ключевого слова <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">implements</code>, за которым идёт название интерфейса. Интерпретатор проверяет, чтобы в классе были описаны все функции интерфейса и их сигнатуры совпадали, а если это не так, то возникает ошибка. Реализация интерфейса никак не ограничивает возможности по наполнению класса, другими словами, вы можете определять и добавлять в класс все, что хотите, помимо интерфейсных функций.</p>
<p>Насколько наличие интерфейсов критично для PHP программ? Например, можно в любой программе открыть все файлы с классами и удалить часть определения класса, которая описывает реализацию интерфейсов (слово <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">implements</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 compare(DecartPointInterface $point1, DecartPointInterface $point2)
{
// ...
}</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 проверяет, реализует ли класс соответствующий интерфейс, и если нет, то возникает ошибка. Причём проверка идёт именно на наличие записи <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">implements</code> в определении класса, а не на факт того, что методы определены (проверка реализации интерфейса гарантирует это).</p>
<p>Такая запись позволяет коду завязываться не на конкретную реализацию точек, а на их интерфейс. Это — ключевая мысль, которую имеет смысл обсуждать подробнее вместе с полиморфизмом.</p>
<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
// Пример из библиотеки DS, внутри которой реализованы различные структуры данных в объектном синтаксисе
// https://github.com/php-ds/polyfill/blob/master/src/Stack.php
class Stack implements \IteratorAggregate, \ArrayAccess, Collection
{
// some code
}</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>Здесь класс <em>Stack</em> реализует сразу три интерфейса. Это значит, что внутри него должны быть реализованы методы всех указанных интерфейсов.</p>
<p><em>Если у разных интерфейсов окажутся методы с одинаковым названием, но разной сигнатурой, то возникнет ошибка. В таком случае придётся отказаться от одного из интерфейсов либо переделать их (например, переименовать методы)</em></p>
<h2 id="heading-2-1">Интерфейс Countable</h2>
<p>В PHP встроен интерфейс <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://php.net/manual/ru/class.countable.php" rel="noopener noreferrer" target="_blank">Countable</a>, а функция <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">count</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
class Collection implements Countable
{
private $items;
public function __construct($items = [])
{
$this->items = $items;
}
public function count()
{
return sizeof($this->items);
}
}
$coll = new Collection([3, 2, 5]);
print_r(count($coll));
// => 3</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div></div><div style="margin-block:var(--mantine-spacing-xl)" class=""><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md)" class="m_8a5d1357 mantine-Title-root" data-order="2">Рекомендуемые программы</h2><style data-mantine-styles="inline">.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:70%;}@media(min-width: 36em){.__m__-_R_2mremqrdub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_2mremqrdub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/php?promo_name=programs_list&promo_position=course&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">10 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">РНР-разработчик</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите PHP и Laravel для разработки и проектирования REST API</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzk5MiwicHVyIjoiYmxvYl9pZCJ9fQ==--e9d0f30948ea766a7e6bc3e3d56c192344d45fb8/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Programming-cuate%20(1).png" alt="РНР-разработчик" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 5 650 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/php-oop?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">2 месяца</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">ООП В PHP</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите архитектуру и чистый код на PHP</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/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1MSwicHVyIjoiYmxvYl9pZCJ9fQ==--e5793a1818ff43d73135cc7ed88c1998d7650470/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Developer%20activity-bro.png" alt="ООП В PHP" 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">от 3 900 ₽</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="/programs/middle-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">5 месяцев</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">Middle-php разработчик</p><p 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="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NTIxNSwicHVyIjoiYmxvYl9pZCJ9fQ==--ee06f514098550b5ac7eebce6227b1543399a37c/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Hand%20coding-rafiki.png" alt="Middle-php разработчик" 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">от 4 050 ₽</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-introduction-to-oop/lessons/interfaces/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 / 18</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-introduction-to-oop/lessons/interfaces/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>