Одними з фундаментальних властивостей об'єктно-орієнтованого програмування є **спадкування** та інкапсуляція. Завдяки цим функціям ви зможете легко будувати складну логіку додатків, зберігаючи при цьому хорошу читабельність реалізації.
Успадкування виражається в тому, що реалізація одного класу базується на іншому. В термінології ООП ми говоримо про нащадка (клас, який успадковує) та предка (клас, який ми успадковуємо).
Загалом, успадкування працює так, що нащадок отримує всі ознаки предка, або переймаючи їх точно такими, якими вони були у предка, або видозмінюючи їх на свій лад, або повністю перекриваючи їх і використовуючи власну реалізацію.
Застосування цього підходу дуже широке, і успадкування використовується низкою паттернів дизайну.
Спадкування добре підходить для проектування так званих представників, які є особливим видом класів, що представляють логіку зв'язку в патерні проектування MVC.
Наприклад, нехай у нас є тріо сторінок "Головна", "Контакти" та "Вхід".
У міру реалізації кожної сторінки значна частина логіки буде повторюватися (наприклад, прийняття запиту, побудова URL-адреси, рендеринг шаблону і відправка отриманого HTML). Тому зручно реалізувати єдиного предка з такою логікою і просто використовувати його в нащадках.
Почнемо з того, що спочатку визначимо предка (ім'я класу не має значення, я використовую угоду з фреймворку Nette):
abstract class BasePresenter{public function link(string $route, array $params = []): string{// реалізація методу побудови URL-адреси}public function renderTemplate(string $path, array $params = []): string{// логіка рендерингу шаблону}}
При визначенні класу я використав нове ключове слово abstract
, яке говорить про те, що клас BasePresenter
є абстрактним. Це означає, що ми не можемо створити його екземпляр, а тільки використовувати його так, щоб інший клас успадкував і реалізував його. Абстракція має й інші корисні переваги, про які ми поговоримо пізніше. Клас не обов'язково повинен бути абстрактним, щоб бути успадкованим - це лише один з можливих варіантів.
Тепер ми можемо реалізувати другий клас, наприклад HomepagePresenter
:
final class HomepagePresenter extends BasePresenter{public function run(): void{// логіка рендерингу$this->renderTemplate('домашня сторінка', ['contactLink' => $this->link('Контакт:за замовчуванням'),]);}}
Тепер у вас є робочий клас HomepagePresenter
. Зверніть увагу, що клас є фінальним
, а це означає, що його вже не можна успадковувати, що гарантує використання методів саме так, як ми їх задали.
Коли ми реалізовували клас, ми створили новий метод run()
, який може обробляти тільки HomepagePresenter
. Всередині методу викликаємо метод renderTemplate()
та link()
, які клас не містить. Однак це не має значення, оскільки ключове слово extends
вказує нам, звідки повинні бути успадковані методи, тому вони використовуються.
Завдяки успадкуванню ми змогли досягти багаторазового використання коду, оскільки після написання методи можуть бути використані в різних місцях.
Дуже часто буває корисно перевизначити поведінку того чи іншого методу при успадкуванні. Наприклад, якби ми захотіли змінити поведінку методу link()
з попереднього прикладу в ContactPresenter
, то це виглядало б так:
final class ContactPresenter extends BasePresenter{public function run(): void{// логіка рендерингуecho $this->link('Головна сторінка:за замовчуванням', []);}public function link(string $route, array $params = []): string{return 'https://baraja.cz';}}
Щоб перевизначити реалізацію, достатньо знову визначити метод у дочірньому класі та перевизначити тіло методу. Головне, щоб відповідати інтерфейсу та реалізовувати однакові вхідні аргументи.
Іноді деякі методи хотілося б приховати при успадкуванні і використовувати тільки для внутрішнього користування. Або ж дозволити їх використання лише під час успадкування, а не в якості публічного інтерфейсу.
Загалом, таким чином, є кілька простих правил видимості. Ми позначаємо методи як "публічні", "захищені" або "приватні", а правила видимості є наступними:
link()
у попередньому прикладі).У дуже специфічних випадках може бути корисно змінити видимість методу під час виконання, а потім викликати його. Цим користуються, наприклад, різні бібліотеки Доктрини.
Для зміни видимості ми потім використовуємо нативний клас ReflectionClass, реалізований самим PHP.
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | uk