4

Полиморфизм

Сначала определение из википедии - способность функции обрабатывать данные разных типов.

Полиморфизм Опрос, Программирование, Oop, Ооп, IT, Длиннопост

1 + '1' и другие приколы

PHP - язык с динамической и слабой типизацией, это значит, что в процессе работы программы тип переменной может быть изменен. Более того, операнды не обязаны быть одного типа и интерпретатор сможет обработать такие варианты операций без ошибок:

<?php

echo 1 . 1; // 11

echo PHP_EOL;

echo 1 + 1; // 2

echo PHP_EOL;

echo 1 + '1'; // 2

?>

Такое поведение уже формально подпадает под определение, но мы конечно хотим от полиморфизма совсем другого.

Практическая польза от полиморфизма в том, чтобы использовать один и тот же код для обработки данных полученных из разных функций, классов файлов и других источников.

Например, у нас есть новостной сайт. И мы получаем из базы данных информацию о новостях, чтобы вывести их пользователю. Чтобы не подключать бд к php песочнице, определим формат новости как json объект:

{

"title": "This is title",

"text": "This is text",

"time": "2024-01-13 12:00:00"

}

Напишем функцию, которая разберет этот json на отдельные поля и выведет на экран с нужным форматированием.

<?php

$jsonString = '{"title": "This is title", "text": "This is text", "time": "2024-01-13 12:00:00"}';

function publish($jsonString){

$jsonObject = json_decode($jsonString);

echo "<h1>$jsonObject->title</h1>";

echo PHP_EOL;

echo "<p>$jsonObject->text</p>";

echo PHP_EOL;

echo "<span>$jsonObject->time</span>";

}

publish($jsonString);

?>

Пока что неплохо справляемся и без ооп с полиморфизмом. Давайте добавим на наш сайт не только новости, но еще и статьи. В статьях не будет времени публикации, но будет имя автора. К сожалению, наша функция перестанет работать, если мы передадим такой json в нее. И тогда надо писать другую. И так для каждого типа контента. Конечно можно добавить несколько if - else и перерисовать дизайн блоков в зависимости от типов, но есть способ получше.

Теперь нам придется написать несколько классов.

<?php

class News

{

private $jsonString;

public function __construct()

{

$this->jsonString = '{"title": "This is title", "text": "This is text", "time": "2024-01-13 12:00:00"}';

}

public function publish()

{

$jsonObject = json_decode($this->jsonString);

echo "<div class='news'>";

echo "<h1>$jsonObject->title</h1>";

echo "<p>$jsonObject->text</p>";

echo "<span>$jsonObject->time</span>";

echo "</div>";

}

}

class Article

{

private $jsonString;

public function __construct()

{

$this->jsonString = '{"title": "This is title", "text": "This is text", "author": "Pikabu Member"}';

}

public function publish()

{

$jsonObject = json_decode($this->jsonString);

echo "<div class='article'>";

echo "<h2>$jsonObject->title</h2>";

echo "<p>$jsonObject->text</p>";

echo "<span>$jsonObject->author</span>";

echo "</div>";

}

}

$contents[] = new News();

$contents[] = new Article();

foreach($contents as $content){

$content->publish();

echo PHP_EOL."<div class='divider'></div>".PHP_EOL;

}

?>

Классы News и Article имеют одно приватное свойство jsonString. Заполняют его при создании объекта в конструкторе и выводят информацию из этого свойства в методе publish.

Таким образом мы можем использовать один метод для отрисовки данных из разных классов. И в главном потоке программы использовать простую конструкцию foreach(){$content->publish} для вывода разных отформатированных блоков.

Кто-то также говорит, что многие реализации должны принадлежать одному интерфейсу. То есть, мы должны определить общий интерфейс для классов его реализующих. На этапе вызова общего метода проверить принадлежность к интерфейсу. Таким образом мы сможем расширять программу многими классами и не задумываться об изменении главной программы.

<?php

interface IContent

{

function publish();

}

class News implements IContent

{

private $jsonString;

public function __construct()

{

$this->jsonString = '{"title": "This is title", "text": "This is text", "time": "2024-01-13 12:00:00"}';

}

public function publish()

{

$jsonObject = json_decode($this->jsonString);

echo "<div class='news'>";

echo "<h1>$jsonObject->title</h1>";

echo "<p>$jsonObject->text</p>";

echo "<span>$jsonObject->time</span>";

echo "</div>";

}

}

class Article implements IContent

{

private $jsonString;

public function __construct()

{

$this->jsonString = '{"title": "This is title", "text": "This is text", "author": "Pikabu Member"}';

}

public function publish()

{

$jsonObject = json_decode($this->jsonString);

echo "<div class='article'>";

echo "<h2>$jsonObject->title</h2>";

echo "<p>$jsonObject->text</p>";

echo "<span>$jsonObject->author</span>";

echo "</div>";

}

}

$contents[] = new News();

$contents[] = new Article();

foreach($contents as $content){

if ($content instanceof IContent) {

$content->publish();

echo PHP_EOL."<div class='divider'></div>".PHP_EOL;

}

}

?>

Вместо заключения. Хоть праздники уже закончились, но статью я дописал только сейчас, поэтому - Желаю всем счастливого нового года, денег, тепла и мира.

Спасибо всем, кто смог дочитать этот пост до конца несмотря на ужасное оформление, примеры на php и общую безграмотность. Отдельное спасибо всем, кто заходит и подписывается на ютуб канал. Я начинаю готовить видео на тему ООП. Может быть примеры кода на видео будут более понятны.

Ссылки на полезные документы:

Ну и в конце добавлю опрос

Что рассмотрим в следующий раз?
Всего голосов:

Лига программистов

2K пост11.8K подписчиков

Правила сообщества

- Будьте взаимовежливы, аргументируйте критику

- Приветствуются любые посты по тематике программирования

- Если ваш пост содержит ссылки на внешние ресурсы - он должен быть самодостаточным. Вариации на тему "далее читайте в моей телеге" будут удаляться из сообщества