Всем привет! Помогите понять полиморфизм правильно. Так как примеров в Интернете много и все они отличаются друг от друга. Как я его понимаю. Это когда свойство базового класса может использовать методы производных классов. Часто встречаю в Интернет два примера полиморфизма : Первый. PHP: class user { public $type = 'default_user'; public function setName (){ } public function Call (){ return $this->setName(); } } class admin extends user { public function setName (){ return $this->type = "admin"; } } class superUsers extends user { public function setName (){ return $this->type = "superUser"; } } $super = new superUsers; $admin = new admin; echo $super->call(); echo $admin->call(); Второй. PHP: class user { public $type = 'default_user'; public function setName (){ } } class admin extends user { public function setName (){ return $this->type = "admin"; } } class superUsers extends user { public function setName (){ return $this->type = "superUser"; } } $super = new superUsers; $admin = new admin; echo $super->setName(); echo $admin->setName(); Чем-то эти два примера отличаются друг от друга ?
@ntn, что именно тебя запутало в этом коде? В первом коде результат получается вызовом метода call() в котором в свою очередь вызван метод setName(), а во втором примере идет обращение напрямую к методу setName().
Так как я понял и в первом примере и во втором примере показан полиморфизм , а называется этот вид override (переопределение). Все верно я понял ?
@ntn, полиморфизм это возможность выполнять одну и ту же операцию в различных классах по разному. А переопределение это скорее необходимость, иначе выполнить действие по другому никак не удастся. А где ты читаешь про ООП?
Плохой пример полиморфизма. Полиморфизм - это когда ты можешь обращаться с объектом производного класса, как с объектом базового класса. Вот получше пример, хотя для краткости всё-равно надуманный PHP: abstract class NamedAnimal { abstract function showName(); } class Cat extends NamedAnimal { function showName() { echo "кошка"; } } class Dog extends NamedAnimal { function showName() { echo "Собака"; } } function sayHelloToAnimal(NamedAnimal $a) { echo "Привет, "; $a->showName(); } sayHelloToAnimal(new Cat()); sayHelloToAnimal(new Dog()); --- Добавлено --- Т.е. функции sayHelloToAnimal всё равно какой объект принимать, главное чтоб он был наследником NamedAnimal, и он будет вызывать правильную функцию showName(), в зависимости от того, что в неё передаёт
@mkramer, между твоим примером и его разницы практически никакой нету. А функция ниже, не имеет отношения к полиморфизму. Это обычная функция со строго-типизированным локальным параметром, который в свою очередь является объектом типа NamedAnimal. А полиморфизмом же является возможность выполнять функцию showName() в разных реализациях по разному.
@mahmuzar, как раз таки имеет. Полиморфизм - многоформие. Т.е. функции sayHelloToAnimal всё равно с каким наследником. работать Она считает, что она работает с объектом класса NamedAnimal, но будет правильно отрабатывать и с Cat, и с Dog, хотя даже не знает, какой из них к ней пришёл - ей всё равно. Это ярче видно в языках типа C++, где методы по-умолчанию фактически final, и так не работают, и их нужно отдельно объявлять виртуальными. А в php наоборот, функции по умолчанию виртуальные. Большая часть паттернов именно на этом основано, кстати говоря. --- Добавлено --- А в примерах ТС там создали объект superAdmin, вызвали его функцию - вызвалась его функция, ничего неожиданного и особенного
Ей не всеравно, функция ждет конкретный тип. NamedAnimal не может иметь объектов, функция ожидает объект типа NamedAnimal. ну да, они собственно является типом NamedAnimal. Не функция sayHelloToAnimal должна определить какой метод вызывать объекту $a. При вызове метода showName() сначала проверяется не переопределен ли он в дочерном классе, если да, то вызывается реализация дочерного класса. Т.е. функция переопределена и поведение будет другим, это и есть полиморфизм. --- Добавлено --- Как я понял, полиморфизм это характеристика поведения нежели объектов.
https://habrahabr.ru/post/37576/ --- Добавлено --- Такая запись в php означает: функция принимает NamedAnimal и все от него производные. Я и написал, что ей всё равно, какой наследник NamedAnimal ей будет передан. Если через 2 года некий дядя Вася сделает ещё одного наследника, Cow, к примеру, она и с этим наследником будет работать. --- Добавлено --- http://www.studfiles.ru/preview/5124065/ - вот здесь тоже хорошо
@ntn в первом примере у класса user есть метод Call. Этого метода нет в классах admin и superUser. Получается, когда ты вызываешь Call, этот метод исполняется в классе user. Однако когда Call пытается вызывать setName, он использует не собственный setName, а setName наследника. Нужно помнить, что переменные $super и $admin являются переменными класса user, что подтверждается с помощью instanceof или хинтинга в примере @mkramer. Это пример полиморфизма. Мне нагляднее представлять полиморфизм как наследование наоборот. Предположим, у нас есть базовый класс PHP: class Basic { function doOne() { echo "Basic One\r\n"; } function doTwo() { echo "Basic Two\r\n"; } function doSomething() { echo "Basic Something\r\n"; } function start() { $this->doOne(); $this->doTwo(); $this->doSomething(); } } Ситуация 1. В базовом классе реализован один нужный тебе метод - doOne(). Чтобы не изобретать и не копипастить, ты просто наследуешь его в своем классе PHP: function process(MyWork $var) { $var->start(); } // Я кул-хацкер, заюзал готовый класс Basic в своей работе, // чтобы сэкономить на написании кода class MyWork extends Basic { function doTwo() { echo "My Two\r\n"; } function doSomething() { echo "My Something\r\n"; } function start() { $this->doOne(); $this->doTwo(); $this->doSomething(); } } process(new MyWork); Ситуация 2. Существует законченная программа, в определенном месте которой нужно изменить поведение одного метода. Её функции работают с классом Basic и ничего не хотят слышать про MyWork. Ты легко решаешь задачу благодаря полиморфизму: PHP: function process(Basic $var) { $var->start(); } // Я кул-хацкер, с помощью полиморфизма видоизменил базовый класс, // и подсунул его в функцию так, что этого никто не заметил class MyWork extends Basic { function doTwo() { echo "My Two\r\n"; } } process(new MyWork);
Он дал очень плохое определение полиморфизму. Очень сложно понять. Статя не плохая спасибо. Это не есть полиморфизм, это не имеет отношения к полиморфизму, то что функция может принимать любой объект типа NamedAnimal. Это просто уточнение типа. Полиморфизм есть изменение поведения метода. Первая статья хорошая, а вторая мне совсем не понравилось. Вы все сговорились)). Не с классом а с типом)
Мы в PHP!) У всех этих переменных тип object. В PHP всего 9 типов. Открыл про полиморфизм в вики, там пишут про полиморфизм функций. Отличный пример этого на C++ расписан здесь https://www.programiz.com/cpp-programming/function-overloading В зависимости от переданных при вызове типах переменных, исполняются разные реализации функции. Предполагается, что результат работы функции будет примерно одинаков. Это дает офигенный профит! Программист вдруг может подзабить на приведение типов перед вызовом функции. Для него функция как будто подстраивается под его переменные в строго типизированном языке! А вот в статье про ООП в той же вики такое определение В моём примере решение второй ситуации эквивалентно имплементации интерфейса Basic на класс MyWork.
Ну раз речь об ООП то правильнее говорить тип а не класс, потому что один объект может иметь несколько типов, в твоем примере как раз так и есть, объект имеет тип MyWork и Basic. Я ничего не имею против твоего кода, да, там есть полиморфизм, ты комментом даже выделил где именно полиморфизм. Но функция process() не имеет отношения к полиморфизму. Именно с этим я не согласился с @mkramer. --- Добавлено --- Поэтому я и написал, что его код и код автора темы идентичны за исключением функции с проверкой типа которая отношения к полиморфизму не имеет.
@mahmuzar да, функция process() в моём коде чисто символическая. Про терминологию, всё-таки функция gettype() скажет "object", а is_a() покажет что у переменной несколько классов.
Все таки в PHP недоООП если сравнивать с другими строго-типизированными языками. Например в java все объекты имеют тип Object и проходят проверку типа в функции. А в PHP как бы пишет тип Object но при проверке типа пишет что ожидается тип Object. Если верить Мэтт Зандстра, то класс так же определяет тип имени себя, но на более высоком уровне. Поэтому объект относится к элементарному типу object и к типу своего класса, а так же унаследованного класса. В итоге все объекты имеют тип Object, но проверку на тип Object при передаче в функцию не проходят.