Полиморфизм 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 ‘

Новость

‘ ;
//.
>
>
class Announcement extends Publication // переопределяем абстрактный метод печати
public function do_print() echo ‘

Объявление

‘ ;
//.
>
>
class Article extends Publication // переопределяем абстрактный метод печати
public function do_print() echo ‘

Статья

‘ ;
//.
>
>

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

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

Читайте также:  Ленивая загрузка java hibernate

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

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

Источник

Полиморфизм в ООП на PHP

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

Что такое полиформизм?

Полиморфизм — это, по сути, шаблон ООП, который позволяет множеству классов с разными функциями выполнять или совместно использовать общий интерфейс.

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

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

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

Как реализовать принцип полиморфизма?

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

Читайте также:  Javascript this element value

В приведенном ниже примере интерфейс с именем Shape фиксирует все классы, реализующие его, для определения абстрактного метода с именем calcArea() :

Пример

Соответственно, класс Circle реализует интерфейс, помещая в метод calcArea() формулу, вычисляющую площадь кругов:

Пример

 radius = $radius; > // calcArea вычисляет площадь круга public function calcArea() < return $this ->radius * $this -> radius * pi(); > > ?>

Класс Rectangle также реализует интерфейс Shape , но определяет метод

с формулой вычисления, которая подходит для прямоугольников:

Пример

 width = $width; $this -> height = $height; > // calcArea вычисляет площадь прямоугольников public function calcArea() < return $this ->width * $this -> height; > > ?>

Теперь мы можем создавать объекты из конкретных классов:

Пример

Мы можем быть уверены, что все объекты вычисляют площадь с помощью метода calcArea() , будь то прямоугольный объект или круговой объект (или любая другая форма), если они реализуют интерфейс Shape .

Теперь мы можем использовать методы calcArea() для вычисления площади фигур:

Пример

 class Circle implements Shape < private $radius; public function __construct($radius) < $this ->radius = $radius; > // calcArea вычисляет площадь круга public function calcArea() < return $this ->radius * $this -> radius * pi(); > > class Rectangle implements Shape < private $width; private $height; public function __construct($width, $height) < $this ->width = $width; $this -> height = $height; > // calcArea вычисляет площадь прямоугольников public function calcArea() < return $this ->width * $this -> height; > > $circ = new Circle(3); $rect = new Rectangle(3,4); echo $circ -> calcArea(); echo $rect -> calcArea(); ?>

Результат выполнения кода:

Вывод

В этом уроке мы узнали, как реализовать принцип полиморфизма в PHP. Кликните здесь, чтобы попрактиковаться в предмете.

Источник

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

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

Однако перед этим давайте вспомним конструкцию instanceof. Она позволяет узнать, является ли объект экземпляром какого-то класса, либо что он реализует какой-либо интерфейс. Возвращает true или false.

class A < public function sayHello() < return 'Hello, I am A'; >> $a = new A(); var_dump($a instanceof A); // true

Давайте создадим ещё один класс, который будет наследником класса A, и выполним ту же проверку для объекта этого класса.

class B extends A < >$b = new B(); var_dump($b instanceof B); // true

При этом если проверить объект дочернего класса, является ли он объектом родительского класса, то мы получим true.

class B extends A < >$b = new B(); var_dump($b instanceof A); // тоже true!

Это правило работает только в одну сторону, объекты родительского класса не будут являться экземплярами дочернего.

class A < public function sayHello() < return 'Hello, I am A'; >> class B extends A < >$a = new A(); $b = new B(); var_dump($a instanceof B); // false

Согласитесь, это вполне логично.

Таким образом объекты дочерних классов будут проходить проверку на то, что они являются экземплярами родительских классов.

Как мы помним, методы объектов родительских классов у нас доступны и в дочерних – они наследуются. Соответственно мы можем быть уверены, что эти же методы есть и у дочерних объектов. Конкретно в нашем примере – у объектов класса B будет метод sayHello(), унаследованный от A.

Читайте также:  Javascript delete file from folder

Или в примере с интерфейсами из прошлого урока – мы определили, что объекты, реализовавшие какой-то интерфейс обязательно будут иметь метод с определённым набором параметров. То есть мы можем рассчитывать на то, что этот метод у объекта гарантированно есть и мы можем его вызвать.

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

Это свойство, благодаря которому мы можем зависеть не от конкретной реализации (проще говоря конкретного класса), а от абстракции (интерфейса), и есть – полиморфизм.

Да-да, в примере про вычисление площадей фигур мы уже сталкивались с полиморфизмом! В тот момент, когда мы проверяли, имеется ли у объекта интерфейс для вычисления площади, мы работали с проявлением полиморфизма.

Переопределение методов

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

class A < public function sayHello() < return 'Hello, I am A'; >> class B extends A < >$b = new B(); echo $b->sayHello(); // Hello, I am A

Однако, мы можем переопределить этот метод в классе B. Для этого мы описываем метод с таким же названием и описываем в нём свою логику:

class A < public function sayHello() < return 'Hello, I am A'; >> class B extends A < public function sayHello() < return 'Hello, I am B'; >> $b = new B(); echo $b->sayHello(); // 'Hello, I am B

Мы также можем вызвать родительский метод в дочернем при помощи слова parent и двойного двоеточия.

 > class B extends A < public function sayHello() < return parent::sayHello() . '. It was joke, I am B :)'; >> $b = new B(); echo $b->sayHello(); // Hello, I am A. It was joke, I am B :)

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

И ещё один примерчик, тоже искуственный.

class A < public function method1() < return $this->method2(); > protected function method2() < return 'A'; >> class B extends A < protected function method2() < return 'B'; >> $b = new B(); echo $b->method1();

Как думаете, что выведет этот код?

Не знаю, что вы ответили, но он в любом случае выведет B. Внутри метода method1() будет вызван тот метод method2(), который определён для класса, в котором его выполняют. То есть $this не привязан напрямую к классу A. Когда мы вызываем method1() у экземпляра класса B, то $this внутри него будет связан с классом B, и вызовется метод method2(), определенный именно в классе B.

И это – тоже полиморфизм. $this привязывается к объекту, в котором код выполняется, а не там, где он был описан.

На этом с полиморфизмом пока всё, если что-то непонятно – пишите в комментах.

Источник

Оцените статью