ООП. Полиморфизм

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

Так что же это такое?

Вообще, когда я думал над этим понятием, мне пришло в голову то, что полиморфизм - это способность, так скажем, объекта изменять свою форму. Или использовать много разных форм. В общем что-то вроде того :) Я рассуждаю на основе собственного опыта программирования на языке C#.

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

Не сразу понятно? Я когда изучал эту вещь, тоже не сразу понял :)

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

Представим, что у нас есть базовый класс «Геометрическая фигура» и есть четыре производных класса: «Треугольник», «Эллипс», «Прямоугольник» и «Круг». Нам нужно реализовать рисование этих фигур с использованием полиморфизма:

<?
    // Класс Фигуры (какой фигуры - неизвестно. просто фигуры)
    abstract class Figure {
        abstract public function Draw(); // абстрактный метод «Нарисовать фигуру»
    }

    // Класс Треугольника
    class Triangle extends Figure {
        public function Draw() {  // метод «Нарисовать треугольник»
            echo 'рисуем треугольник';
        }
    }

    // Класс Эллипса
    class Ellipse extends Figure {
        public function Draw() {  // метод «Нарисовать эллипс»
            echo 'рисуем эллипс';
        }
    }
   
    // Класс Круга
    class Circle {
        public function Draw() {  // метод «Нарисовать круг»
            echo 'рисуем круг';
        }
    }

    // Класс Прямоугольника
    class Rectangle extends Figure {
        public function Draw() {  // метод «Нарисовать прямоугольник»
            echo 'рисуем прямоугольник';
        }
    }



    // обыкновенная функция рисования фигуры
    function drawFigure($fig) {
        if ($fig instanceof Figure) {
            $fig->Draw(); // тут мы на этапе написания этой функции не знаем,
                          // какая именно фигура будет рисоваться, а интерпретатор
                          // php это знает только на этапе выполнения скрипта
        } else {
            echo 'Неизвестная фигура';
        }
    }


    // создадим фигуры
    $triangle  = new Triangle();  // треугольник
    $ellipse   = new Ellipse();   // эллипс
    $rectangle = new Rectangle(); // прямоугольник
    $circle    = new Circle();    // круг
   
    // нарисуем прямоугольник
    drawFigure($rectangle);
   
    // нарисуем эллипс
    drawFigure($ellipse);
   
    // попытаемся нарисовать круг
    drawFigure($circle);
?>

Тут вся прелесть в том, что функция drawFigure сама «принимает решение», метод Draw какого класса использовать. Она «знает», что есть какая-то фигура, которую мы ей даем, и что ее можно нарисовать. А как она будет рисоваться - это уже забота одного из перечисленных классов.

Приведенный выше скрипт выведет следующее:

рисуем прямоугольник
рисуем эллипс
Неизвестная фигура // хотя здесь кто-то ожидал увидеть «рисуем круг»

Мы увидели, что функция не смогла принять «круг» за геометрическую фигуру. Это все из-за конструкции instanceof. Она позволяет выяснять, является ли объект производным от указанного класса. В нашем случае мы проверили, является ли геометрическая фигура производной от класса Figure. Если посмотрите внимательно на приведенный выше код, то обнаружите, что класс Circle не наследуется от абстрактного класса Figure. Отсюда и сообщение «Неизвестная фигура».

Могу привести еще один пример проявления полиморфности классов:

<?
    class Base {
        function fn() {
            echo "Base";
        }
       
        function get() {
            $this->fn();
        }
    }
   
    class Derived extends Base {
        function fn() {
            echo "Derived";
        }
    }
   
    $b = new Base();
    $d = new Derived();
   
    $b->get(); // выводит "Base"
    $d->fn();  // выводит "Derived"
    $d->get(); // а здесь что выведет?
?>

Как думаете, что будет выведено в последнем случае? Правильно! «Derived». Хотя я изначально думал, что будет выведено “Base”. Эта наивность новичка у меня прошла с выполнением вышеописанного эксперимента :)

А почему “Derived”? Ведь там же вызывается метод get, который вызывает функцию fn текущего объекта! Вот именно. Текущего объекта. Потому что метод get переопределился в классе Derived и теперь он вызывает $this->fn(), а $this указывает на объект класса Derived. Вот и полиморфизм.

На этом я заканчиваю обзор объектно-ориентированных возможностей языка PHP версии 5. Вроде бы все рассказал в этом цикле статей про ООП. Но если что-то забыл - буду рад видеть комментарии к этой статье :)





Читайте также:



18 Ответов на “ООП. Полиморфизм”

  1. Evgeniy

    К сожелению очень не полно :( К тому же это не совсем “настоящий” полиморфиз. Изначально полиморфиз подрозумевает, что мы в одном классе описываем два метода с одним именем, но с разнвым ко-вом или “качеством” аргументов, т.е. Class poli{ function test(str $a){} function test(int $a){} } тогда poli::test(2) вызовет один метод, а poli::test(‘Hello’) вызовет другой, а PHP при наследовании, сначала ищется метод в текущем классе, а потом, если не найден, ищется в родительском. Так что не путайте новичков.

  2. Анатолий

    спасибо за статьи оч. помогли разобраться

  3. Интересный пример полиморфизма -
    [ссылка]

  4. сергей

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

  5. Jenia

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

  6. Trip

    Согласен с выше приведенными комментариями. Статья удачно демонстрирует возможности РНР, но паршиво объясняет основную идею полиморфизма как такого.

  7. не знаю почему все так возмущаются. Показан пример “полиморфизма” так, как его можно на практике использовать. Разве не это главное?

  8. dar

    Первый комментарий абсолютно неверный в корне. то что описывает господин Evgeniy не полиморфизм, а обычная перегрузка методов. полиморфизм же возникает при переопределении методов. Перегрузка возникает тогда, когда в рамках одного класса, существуют одноименные с разными сигнатурами (параметрами).
    Пример:1) ShowTheList($Mylist $NewLIst)
    2) ShowTheList()
    К полиморфизму это не имеет никакого отношения.
    Полиморфизм (многоформенность) возникает тогда, когда в рамках единой иерархии классов существуют одноименное методы с полностью одинаковыми сигнатурами. А именно возникает переопределение (overriding) методов. А не перегрузка (overloading).
    Полиморфизм как таковой достаточно сложная для понимания штука, и в данной статье действительно немного не полно описана суть. а так все верно.

  9. Evgeniy

    Комментарий dar
    Полиморфизм (многоформенность) возникает тогда, когда в рамках единой иерархии классов существуют одноименное методы с полностью одинаковыми сигнатурами.
    ____________
    Ok, как интерпретатор PHP будет различать какой из методов вызывать?

  10. Алексей

    Очень даже ничего. Спасибо за примеры.

  11. programmer

    Интересно!
    А вот последний пример если написать в C# и запустить, то при вызове функции fn() из метода get() вызывается функция fn() текущего класса а не текущего объекта!

  12. Xucyc

    Для начала, я бы сказал очень хорошо! т.к. новичку разобраться не сложно и если понял суть, будет проще разобраться в больших примера полиморфизма.
    Спасибо автору за труд!

  13. Роман

    а class Circle то не extends Figure ))

  14. Ostap

    так і має бути))

  15. Dimass

    Evgeniy, это уже дело самого интерпретатора. Если вам так интересно почитайте мануал по пхп раздел “Ядро PHP: Руководство хакера по Zend Engine” там подробно про внутренности рассказано. Я же скажу что в статье все верно описано про полиморфизм в PHP.

  16. спасибо, все отлично сказано!

  17. Movses

    Спасибо за примеры, все отлично сказано!

  18. Ivan

    vse chetko i yasno! respect


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map