Об’єктно-орієнтоване програмування в WordPress – Спадкування. Частина I
Об’єктно-орієнтоване програмування в WordPress – Спадкування. Частина II

У попередній статті ми представили концепт об’єктно-орієнтованого спадкування, спробували описати його з точки зору не професіоналів, а потім розглянули високорівневу концептуальну модель того, як спадкування працює в контексті програмування.

Так, ми вже охопили багато, але для того, щоб закласти основу для початківців — міцний фундамент, відштовхуючись від якого можна було б почати писати об’єктно-орієнтований код на PHP, потрібно багато чого вивчити.

Спадкування — це предмет обговорення, в якому ми починаємо занурюватися вже у допоміжні теми, тому дана стаття є заключною огляд базових концепцій, після якого ми завершимо нашу серію узагальнюючої статті.

Огляд спадкування

Нагадаємо, що ми визначили спадкування наступним чином:

Спадкування — це механізм, при якому один клас служить в якості батьківської для дочірнього класу, що забезпечує ряд властивостей і методів, загальних для батьків, і для дитини; при цьому дитина має здатність вводити свої власні властивості.

Це визначення дещо менш формально, ніж те, яке ви можете знайти в підручниках, чи навіть в Вікіпедії, але воно пояснює ідею в термінах, які ілюструють суть спадкування.

У цій статті ми розглянемо весь необхідний код, функції і зарезервовані слова, що відносяться до теми; ми обговоримо те, як можна реалізувати спадкування на PHP дуже-дуже простим платформо-незалежною способом, а потім ми розглянемо фактичну реалізацію спадкування в WordPress.

Отже, план дій намічений, давайте приступимо.

Можливості PHP

Для того щоб реалізувати спадкування в об’єктно-орієнтованому PHP, існує ряд зарезервованих слів, з якими нам потрібно познайомитися. На щастя, більшість слів ми вже розглянули, а ті, що залишилися, достатньо зрозумілі, щоб їх легко запам’ятати.

Тому перш ніж ми поринемо в розбір коду, давайте розглянемо всі зарезервовані слова мови, які нам потрібно знати, щоб ми могли дійсно приступити до створення чого-небудь:

  • extends — це зарезервоване слово, яке показує, що один клас є дитиною іншого класу. Наприклад, в нашій попередній статті, клас Post розширює Content. Ми скоро побачимо це на справі;
  • private — це атрибут, який застосовується до властивостей і функцій, і означає, що вони доступні тільки в контексті класу, в якому вони оголошені;
  • protected схоже на ключове слово private за тим винятком, що властивості і методи, оголошені таким чином, будуть доступні даного класу і будь дочірнім класів;
  • public має значення, протилежне private — будь-клас: даний клас, підклас і будь-який сторонній клас, можуть отримати доступ до цієї властивості або методу для того, щоб змінити міститься в ньому інформацію або викликати функцію.

Вам також потрібно знати оператор ::, але ми обговоримо його в цій статті трохи пізніше, коли почнемо розбирати код.
Ось і все — нічого жахливо складного, чи не так? І до того ж, якщо ви стежили разом з нами за тим, що відбувається в цій серії статей, то ймовірно, ви знайомі з усіма словами за винятком extends.

Як би те ні було, давайте почнемо розбирати приклад.

Деякі приклади коду

Для того щоб почати писати код, нам необхідно точно з’ясувати що ж ми збираємося моделювати (і, зрештою, що код робить, чи не так?).

Щоб залишатися послідовним і підтримати зв’язок з усією серією статей — особливо з останньої — у нас буде батьківський клас Content і два підкласи, які ми назвемо Comment та Post відповідно.

Це дозволить нам подивитися, як властивості і методи функціонують в рамках окремого класу, і як дочірні класи можуть отримати доступ до атрибутів їх батьків, а також як батьки можуть захистити свої властивості і функції від своїх підкласів.

Однак практична реалізація може продемонструвати набагато більше, ніж просто слова, тому давайте почнемо писати код.

Батьківський клас

У нашому прикладі батьківський клас — це клас Content, так як обидва його підкласу, Post і Comment, є типами вмісту, які мають унікальну інформацію, що відноситься до них, але не пов’язану з класом Content.

Головне в спадкуванні — це виявити всі властивості і методи, загальні для всіх класів і помістити їх визначення в батьківському класі, в нашому випадку, в класі Content.

Хоча ця частина може змінюватись в залежності від того, як до цього підійти, ми задамо клас Content так, що він буде містити в собі наступну інформацію:

  • дата публікації контенту;
  • автор;
  • метод збереження;
  • метод форматування вмісту;
  • метод отримання контенту;
  • метод отримання автора.

Спочатку, давайте подивимося код, а потім розберемо все, що в ньому відбувається:

publish_date = $date->format( ‘Y-m-d H:i:s’ );
$this->author = «;
}
public function save( $author, $content ) {
$this->author = $author;
$this->content = $this->format_content( $content );
$this->content;
}
public function read() {
return $this->content;
}
private function format_content( $content ) {
return strip_tags( stripslashes( $content ) );
}
public function get_author() {
return $this->author;
}
}

Як зазначалося вище, у нас є два атрибута типу protected і один private атрибут. Нагадаю, що це означає, що всі підкласи можуть отримати доступ до змінних $publish_date і $author, але до атрибуту $content може звертатися тільки екземпляр класу Content.

Також прошу зауважити, що більша частина коду, яку ви бачите в класі, наведеному вище, є базовим об’єктно-орієнтованим кодом, написаним на PHP. Там немає нічого, що мало б пряме відношення до спадкування, крім деяких модифікаторів доступу, які ми оголосили. Тобто можна сказати, що цей код схожий на той, що ми вже бачили в уроках.

Варто відзначити, що private функція використовується, щоб продемонструвати дві речі:

  • До private функцій можна звертатися тільки в контексті класу, де вони були оголошені.
  • Всі теги і слеші будуть видалені з контенту, так що розмітка не зберегтися разом з контентом.

Звичайно, цей код не підключається до бази даних або файловій системі або чого-небудь ще, але суть від цього не змінюється.

Зверніть увагу, що в коді, наведеному вище, є кілька речей, які нам довелося додати, щоб дотримати вимоги PHP. Це виходить за рамки даної статті, але варто відзначити наступне:

  • Код date_default_time_set необхідний, щоб встановити часовий пояс, для якого буде вилучатись час.
  • Конструктор відповідальний за початкову установку дати публікації контенту, крім того, властивість author в ньому ініціалізується порожнім рядком. Це зроблено тому, що об’єкти класів Post і Comment можуть мати своїх власних авторів. І як ми побачимо далі, примірник Comment може навіть змінити дату публікації, задану за замовчуванням.

Зазначу також, що ми можемо отримати контент за допомогою методу read і отримати автора допомогою функції get_author.

Перша дитина

Давайте продовжимо. Створимо підклас Post. Спочатку поглянемо на код, а потім подивимося, як клас Post взаємодіє з класом Content, який ми тільки що створили:

author = ‘Tom McFarlin’;
}
public function post( $content ) {
$this->format_content( $content );
}
}

Клас виявився невеликим, правда? У ньому немає властивостей, тому що він успадкував їх від класу Content, і є тільки дві функції, одна з яких є унікальною для класу — функція post.

Зверніть увагу, що в конструкторі ми спочатку викликаємо батьківський конструктор за допомогою оператора «::». Ви можете знайти більш детальну інформацію про це в керівництві, але досить сказати, що оператор зарезервований для посилання на різні речі поза класу, в якому він визначений. В нашому випадку, це виклик батьківського конструктора.

Потім, я вирішив встановити своє ім’я як автора посту. Зауважте, що я використовую ключове слово $this. Так як підклас успадковує властивості від свого батька, він може звертатися і до цих властивостями, і до властивостей, певних з тим же ім’ям всередині нього самого.

Зазначу, що це можливо не тільки тому, що клас Post розширює Content, але також тому, що властивість зазначено, як protected в класі Content. Якщо б воно мало ідентифікатор private, це було б неможливо.

Друга дитина

Тепер, коли ми створили клас Post, у нас залишився клас Comment, який, нагадаю, представляє когось, хто залишив коментар до посту.

Якщо б це був код реального проекту, то його було б набагато більше: нам потрібно було б співвіднести коментар з постом, визначити, є чи коментар відповіддю на існуючий коментар, відзначити статус коментаря і так далі.

Однак, щоб показати, як працює спадкування, ми не зупиняємося на всіх цих деталях, а зосереджуємося лише на те, що демонструє основні ідеї:

save( ‘John Doe’, $comment );
}
}

Як ви можете побачити, код класу Comment не сильно відрізняється від коду класу Post. Якоюсь мірою це добре, тому що показує, що ми зробили правильний абстрагування відповідних частин у нашому базовому класі.

Як би те ні було, зверніть увагу, що після створення об’єкта класу Comment, ми викликаємо наш батьківський конструктор. Потім ми визначаємо метод add, який відповідальний за прийняття вхідного коментаря та його збереження шляхом передачі автора коментаря та вмісту метод save.

Примітно, що метод save вже визначено у базовому класі, який також обробляє всі форматування за допомогою private функції. Таким чином, ми отримали необхідний функціонал, створивши наш дочірній клас.

Приклади

Коли все готово, давайте виконаємо кілька прикладів, щоб показати, як окремі частини функціонують один з одним. Для того щоб переконатися, що код виконується, вам знадобиться веб-сервер, каталог, з якого будуть запускати PHP скрипти і текстовий редактор.

Спочатку ми створимо екземпляр класу Content, а потім звернемося до налагоджувальної інформації, щоб побачити, що являє собою екземпляр класу:

$content = new Content();
var_dump( $content );

Якщо все працює правильно, ви повинні побачити те, що наведено вище.

Рухаємося далі. Створимо екземпляр класу Post. Оскільки ми задаємо всю інформацію всередині самого класу, все, що нам дійсно потрібно зробити, це викликати функцію класу для відображення інформації.

Наприклад:

$post = new Post();
echo ‘The post author is:’ . $post->get_author();

Знову ж таки, так як ми поставили все на самому коді, виклик методу просто демонструє концепцію.

Нарешті, ми можемо створити екземпляр класу Comment, викликати для нього метод add, спробувати передати підозрілий код (тільки щоб подивитися як він буде оброблений нашою програмою). Якщо все йде як треба, ви повинні побачити наступне:

$comment = new Comment();
$comment->add( ‘alert(«This is my comment.»);’ );
echo ‘The comment reads:’ . $comment->read();

Ось і все: наша проста демонстрація спадкування завершена.

Спадкування у WordPress

Коли мова заходить про спадкування в WordPress, перша думка, яка приходить мені в голову (і, ймовірно, іншим розробникам) — це Widgets API. І причиною цього є те, що API функціонує на основі наслідування.

Безумовно, віджети можуть бути створені і без використання API, але я переконаний, що це помилка в розробці. Навіщо все ускладнювати, якщо вже створено основу для роботи? Але я відволікся.

Особливістю цього конкретного API є те, що він демонструє всі основні моменти об’єктно-орієнтованого підходу і спадкування в роботі. Приміром, ось уривок коду, взятої безпосередньо з кодексу WordPress:

Тепер, коли ми обговорили концептуальну модель, розглянули ключові слова і методологію, написали власний код і створили свій приклад, в іншому буде відносно легше розібратися.

Але ось в чому справа: один з кращих способів удосконалюватися в написанні будь-якого типу коду — безперервно практикуватися в концепціях. Тобто вивчати ідеї, реалізовані іншими людьми, які зробили більш складні речі, ніж у попередніх роботах.

В якості прикладу подивіться перший приклад з кодексу WordPress. А якщо ви працюєте з останньою версією PHP, яка підтримує такі функції, як простору імен (трохи більш складна тема), тоді зверніться також до другого прикладу.

Чим більше ви переглядаєте код і копаетесь в ньому, тим більше ви дізнаєтеся. Але якщо ми заглибимося далі, то вийдемо за рамки всієї серії статей.

Переклад статті «Object-Oriented Programming in WordPress — Inheritance II» був підготовлений дружною командою проекту Сайтостроение від А до Я.