21 August 2008

Что такое полиморфизм на самом деле. В PHP он тоже существует.

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

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

Итак, на чем основан полиморфизм.
Мы имеем класс или интерфейс (далее интерфейс), который будет являться каркасом, надстройкой и пр. Этот интерфейс будет определять общее поведение всех своих наследников, т.е. как будут называться их основные действия (методы). Ну а наследники, в свою очередь, могут переопределять эти методы, т.е. задавать индивидуальное поведение данных методов. Эта часть была представлена в статье
s_a_p'а
. Но это только основа полиморфизма. Сама же его суть заключается в том, что мы гарантируем себе, что все методы интерфейса будут вести себя «правильно» независимо от того, какой конкретно производный класс используется. Возможно сейчас это не совсем понятно, но ниже я приведу пример, где ситуация прояснится.

Я не буду углубляться непосредственно в сам полиморфизм и не стану писать о полиморфизме времени и компиляции. Будем ближе к теме данного блога, а именно к PHP.

Полиморфизм в PHP

Язык PHP поддерживает полиморфизм в том смысле, что позволяет использовать вместо экземпляров родительского класса экземпляры подкласса. Ввод в действие требуемого метода осуществляется на этапе прогона. Поддержка перегрузки методов, при которой ввод метода в действие осуществляется с учетом сигнатуры метода, отсутствует. Дело в том, что в каждом классе может присутствовать только один метод с определенным именем. Но благодаря тому, что в языке PHP применяется слабая типизация и поддерживается переменное количество параметров, появляется возможность обойти это ограничение. Если вам интересно, могу поделиться знаниями.

Пример полиморфизма в PHP

Возьмем за основу названия классов уже упоминавшейся статьи.
Нашим интерфейсом в данном случае будет абстрактный класс
abstract class Publication {
// определяем правило, что все публикации должны печататься, т.е. иметь метод do_print()
abstract public function do_print();
}

class News extends Publication {
// переопределяем абстрактный метод печати
public function do_print() {
echo '<h4>Новость</h4>';
//...
}
}
class Announcement extends Publication {
// переопределяем абстрактный метод печати
public function do_print() {
echo '<h4>Объявление</h4>';
//...
}
}
class Article extends Publication {
// переопределяем абстрактный метод печати
public function do_print() {
echo '<h4>Статья</h4>';
//...
}
}

//Наполняем массив публикаций объектами, производными от Publication
$publications[] = new News();
$publications[] = new Announcement();
$publications[] = new Article();

foreach ($publications as $publication) {
if ($publication instanceof Publication) { // Если мы работаем с наследниками Publication
$publication->do_print(); // то мы можем смело выводить данные на печать
}
else {
//исключение или обработка ошибки
}
}


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

Надеюсь теперь тема полиморфизма стала более понятной. Как отмечалось выше, если будет интересно, могу написать о переопределении методов, при котором ввод метода в действие осуществляется с учетом сигнатуры. Обращайтесь.
Tags:PHPООПполиморфизмнаследованиеинтерфейсыабстракция
Hubs: PHP
+99
65.8k 163
Comments 82
Top of the last 24 hours