Аннотация: В этой статье будет обсуждаться концепция полиморфизма и ее применение в объектно-ориентированном проектировании. Также будет проанализировано, как использовать полиморфизм в PHP 5, его преимущества и недостатки.
Поддержка позднего связывания была реализована в последних выпусках PHP. Конечно, при использовании функции позднего связывания все еще возникает много проблем. Если вы используете более старую версию PHP (на моем сервере установлена версия PHP 5.0.1), вы можете обнаружить, что поддержка позднего связывания отсутствует. Поэтому обратите внимание, что код в этой статье может не работать в вашей конкретной версии PHP 5.
1. PHP 5 и полиморфизм.
В этой статье хотелось бы обсудить одну из наиболее важных частей объектно-ориентированного программирования — разработку полиморфизма. Чтобы проиллюстрировать проблему, я использую PHP 5. Прежде чем продолжить чтение, поясните, что эта статья не полностью посвящена PHP. Хотя язык добился больших успехов в быстром развитии за последние две основные версии, его объектной поддержке еще предстоит пройти некоторое время, прежде чем он сможет конкурировать с более зрелыми языками, такими как курс C++ или Java.
Если вы новичок в объектно-ориентированном программировании, эта статья может вам не подойти, поскольку эта часть полиморфизма особенная: как только вы ее поймете, вы никогда ее не забудете. Если вы хотите немного узнать об объектном программировании и проектировании и не совсем понимаете, что значит, когда кто-то говорит: «Объект полиморфен», то эта статья для вас.
К концу этой статьи вы должны знать, что такое полиморфизм и как его применять в объектно-ориентированном проектировании, а также понимать преимущества и недостатки объектного программирования в PHP 5.
2. Что такое полиморфизм?
Определение полиморфизма из словаря.com: «Происходит в разных формах, стадиях или типах в независимых организациях или в одной и той же организации без фундаментальных различий». Из этого определения мы можем думать, что полиморфизм Сексуальность — это программный способ описания одного и того же. объект через несколько состояний или фаз. Фактически, его реальный смысл заключается в том, что в реальной разработке нам нужно сосредоточиться только на программировании интерфейса или базового класса и не беспокоиться о конкретном классе (классе), к которому принадлежит объект.
Если вы знакомы с шаблонами проектирования, даже если у вас есть лишь предварительное понимание, вы поймете эту концепцию. Фактически, полиморфизм может быть лучшим инструментом в программировании проектирования на основе шаблонов. Это позволяет нам логически организовывать подобные объекты, так что нам не нужно беспокоиться о конкретном типе объекта при кодировании, более того, нам нужно только запрограммировать желаемый интерфейс или базовый класс; Чем более абстрактно приложение, тем более гибким оно становится, а полиморфизм — один из лучших способов абстрагировать поведение.
Например, давайте рассмотрим класс под названием Person. Мы можем создать подкласс Person с классами David, Charles и Alejandro. У Person есть абстрактный метод AcceptFeedback(), и все подклассы должны реализовать этот метод. Это означает, что любой код, использующий подкласс базового класса Person, может вызвать метод AcceptFeedback(). Вам не нужно проверять, является ли объект Давидом или Алехандро, достаточно просто знать, что это Человек. В результате ваш код должен сосредоточиться только на «наименьшем общем знаменателе» — классе Person.
Класс Person в этом примере также может быть создан как интерфейс. Конечно, есть некоторые отличия по сравнению с вышеперечисленными, в основном: интерфейс не дает никакого поведения, а лишь определяет набор правил. Интерфейс Person требует: «Вы должны поддерживать метод AddFeedback()», в то время как класс Person может предоставить некоторый код по умолчанию для метода AddFeedback() — вы понимаете это так: «Если вы не решите поддерживать AddFeedback(), тогда Вы должны предоставить реализацию по умолчанию. «Как выбрать интерфейс или базовый класс выходит за рамки этой статьи; однако, как правило, вам необходимо реализовать метод по умолчанию через базовый класс. Вы также можете использовать интерфейс, если можете просто обозначить желаемый набор функций, реализуемых вашим классом.
3. Применение полиморфного проектирования.
Мы продолжим использовать пример базового класса Person, а теперь разберем неполиморфную реализацию. В следующих примерах используются разные типы объектов Person — очень неудовлетворительный способ программирования. Обратите внимание, что фактический класс Person опущен. До сих пор нас интересовал только вопрос вызовов кода.
<?php
$name = $_SESSION['имя'];
$myPerson = Person::GetPerson($name);
переключатель (get_class($myPerson)){
дело «Дэвид»:
$myPerson->AddFeedback('Отличная статья!', 'Некоторый читатель', date('Ггг'));
перерыв;
дело «Чарльз»:
$myPerson->feedback[] = array('Некоторый читатель', 'Отличный монтаж!');
перерыв;
дело «Алехандро»:
$myPerson->Feedback->Append('Потрясающий Javascript!');
перерыв;
по умолчанию :
$myPerson->AddFeedback('Ура!');
}
?>
В этом примере показаны объекты с различным поведением, а оператор переключения используется для различения разных объектов класса Person и выполнения соответствующих им правильных операций. Обратите внимание, что комментарии здесь различны для разных условий. В реальной разработке приложений это может быть не так; я просто иллюстрирую различия, существующие в реализациях классов.
В примере ниже используется полиморфизм.
<?php
$name = $_SESSION['имя'];
$myPerson = Person::GetPerson($name);
$myPerson->AddFeedback('Отличная статья!', 'SomeReader', date('Гг-д'));
?>
Обратите внимание, что здесь нет оператора переключения, и, что наиболее важно, отсутствует информация о том, какой тип объекта Person::GetPerson() вернет. А другой Person::AddFeedback() — это полиморфный метод. Поведение полностью инкапсулировано в конкретные классы. Помните: независимо от того, используем ли мы здесь Дэвида, Чарльза или Алехандро, вызывающий код никогда не должен знать, что делает конкретный класс, только базовый класс.
Хотя мой пример не идеален, он демонстрирует базовое использование полиморфизма с точки зрения вызывающего кода. Теперь нам нужно проанализировать внутреннюю реализацию этих классов. Одна из замечательных особенностей наследования базового класса заключается в том, что производный класс может получить доступ к поведению родительского класса. Часто это реализация по умолчанию, но она также может возникать в цепочках наследования классов для создания более сложного поведения. Ниже приведена простая демонстрация этой ситуации.
<?php
класс Человек {
функция AddFeedback($comment, $sender, $date){
//Добавляем отзыв в базу данных}
}
класс Дэвид расширяет Person{
функция AddFeedback($comment, $sender){
родитель::AddFeedback($comment, $sender,
date('Гм-д'));
}
}
?>
Здесь метод Person::AddFeedback сначала вызывается в реализации метода AddFeedback в классе David. Вы можете заметить, что он имитирует перегрузку методов в C++, Java или C#. Имейте в виду, что это всего лишь упрощенный пример, и фактический код, который вы пишете, полностью зависит от вашего реального проекта.
4. Позднее связывание в PHP 5.
По моему мнению, позднее связывание является важной причиной, почему Java и C# настолько привлекательны. Они позволяют методам базового класса вызывать методы, используя «this» или $this (даже если они не существуют в базовом классе или вызов метода в базовом классе может быть заменен другой версией в унаследованном классе). Вы можете считать, что в PHP разрешены следующие реализации:
<?php
класс Человек {
функция AddFeedback($messageArray) {
$this->ParseFeedback($messageArray);
//Запись в базу данных}
}
класс Дэвид расширяет Person{
функция ParseFeedback($messageArray){
// Проведем анализ}
}
?>
Помните, в классе Person нет ParseFeedback. Теперь, если у вас есть эта часть кода реализации (для этого примера), это приведет к тому, что $myPerson станет объектом Дэвида:
<?php
$myPerson = Person::GetPerson($name);
$myPerson->AddFeedback($messageArray);
?>
Произошла ошибка анализа! Общее сообщение об ошибке заключается в том, что метод ParseFeedback не существует или какая-либо подобная информация. Давайте поговорим о позднем связывании в PHP 5! Далее давайте подведем итог концепции позднего связывания.
Позднее связывание означает, что вызов метода не привязан к целевому объекту до последнего момента. Это означает, что когда метод вызывается во время выполнения, эти объекты уже имеют конкретный тип. В нашем примере выше вы вызвали David::AddFeedback(), и поскольку $this в David::AddFeedback() ссылается на объект David, вы можете логически предположить, что метод ParseFeedback() существует, но на самом деле это не так. существуют, поскольку AddFeedback() определен в Person, а ParseFeedback() вызывается из класса Person.
К сожалению, в PHP 5 нет простого способа устранить это поведение. Это означает, что вы можете быть немного бессильны, когда захотите создать гибкую полиморфную иерархию классов.
Должен отметить, что я выбрал PHP 5 в качестве языка выражений для этой статьи просто потому, что этот язык не реализует идеальную абстракцию концепции объекта! Это понятно, поскольку PHP 5 все еще находится в бета-версии. Кроме того, теперь, когда в язык добавлены абстрактные классы и интерфейсы, также следует реализовать позднее связывание.
5. Резюме
На этом этапе вы должны иметь общее представление о том, что такое полиморфизм и почему PHP 5 не идеален для достижения полиморфизма. В общем, вы должны знать, как использовать полиморфную объектную модель для инкапсуляции условного поведения. Конечно, это увеличивает гибкость ваших объектов и означает меньше кода для реализации. Кроме того, вы повышаете ясность своего кода, инкапсулируя поведение, удовлетворяющее определенным условиям (в зависимости от состояния объекта).