Снова о переопределении методов
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 33 из 91.
Вы уже узнали о переопределении методов в главе «Наследование». Теперь давайте изучим, как это связано с полиморфизмом — одной из самых мощных концепций объектно-ориентированного программирования.
Полиморфизм означает «много форм». Когда вы переопределяете метод в дочернем классе, вы придаете этому методу другую форму, сохраняя при этом то же имя. Магия происходит тогда, когда вы работаете с объектами через их родительский тип:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()) . "\n";
echo makeAnimalSpeak(new Cat());
Вывод:
Woof!
Meow!Функция makeAnimalSpeak() принимает любой Animal. Она не знает и ей не важно, получает ли она Dog или Cat. PHP автоматически вызывает правильный переопределенный метод на основе фактического типа объекта во время выполнения.
Это полиморфизм в действии.
Этот подход позволяет писать гибкий код, который работает с семейством связанных объектов, не зная их конкретных типов. Вы сможете добавить новые классы животных позже, и функция будет работать с ними автоматически.
Ключевой момент: Переопределение методов обеспечивает полиморфизм, позволяя различным классам по-разному реагировать на один и тот же вызов метода, который определяется во время выполнения фактическим типом объекта.
Задание
ЛегкоДавайте создадим систему музыкальных инструментов, которая демонстрирует полиморфизм через переопределение методов. Вы создадите базовый класс Instrument и два дочерних класса, каждый из которых издает свой уникальный звук, а затем используете одну функцию для полиморфного воспроизведения любого инструмента.
Вы организуете свой код в четырех файлах:
Instrument.php— Создайте классInstrumentс защищенным свойством$name, устанавливаемым через конструктор. Добавьте методplay(), который возвращает"[name] makes a sound". Это послужит базовым поведением, которое дочерние классы будут переопределять.Guitar.php— Создайте классGuitar, который расширяетInstrument. Подключите родительский файл. Конструктор принимает имя и передает его в родительский конструктор. Переопределите методplay(), чтобы он возвращал"[name] strums a chord".Drum.php— Создайте классDrum, который расширяетInstrument. Подключите родительский файл. Конструктор принимает имя и передает его в родительский конструктор. Переопределите методplay(), чтобы он возвращал"[name] beats a rhythm".main.php— Подключите файлы Guitar и Drum. Создайте функцию с именемperformWith, которая принимает параметр типаInstrument(с указанием типа) и возвращает результат вызоваplay()для него. Эта функция демонстрирует полиморфизм — она работает с любым типом инструмента благодаря указанию типа родительского класса.
Вы получите два входных значения: имя для гитары и имя для барабана. Создайте объекты Guitar и Drum с этими именами. Передайте каждый из них в функцию performWith() и выведите результаты — сначала для гитары, затем для барабана, каждый на новой строке.
Обратите внимание, как performWith() принимает любой Instrument, но PHP автоматически вызывает правильный переопределенный метод play() в зависимости от фактического типа объекта во время выполнения. Это и есть полиморфизм в действии!
Шпаргалка
Полиморфизм означает «много форм» и позволяет объектам разных классов обрабатываться через их родительский тип, сохраняя при этом их специфическое поведение.
Когда вы переопределяете метод в дочерних классах, PHP автоматически вызывает правильную версию на основе фактического типа объекта во время выполнения:
<?php
class Animal {
public function speak() {
return "Some sound";
}
}
class Dog extends Animal {
public function speak() {
return "Woof!";
}
}
class Cat extends Animal {
public function speak() {
return "Meow!";
}
}
function makeAnimalSpeak(Animal $animal) {
return $animal->speak();
}
echo makeAnimalSpeak(new Dog()); // Woof!
echo makeAnimalSpeak(new Cat()); // Meow!
Функция makeAnimalSpeak() принимает любой тип Animal через указание типа параметра. Ей не нужно знать конкретный класс — PHP определяет, какой переопределенный метод вызвать во время выполнения, основываясь на фактическом типе объекта.
Это позволяет создавать гибкий код, который работает с семейством связанных объектов, не зная их конкретных типов. Новые дочерние классы могут быть добавлены позже и будут автоматически работать с существующими функциями.
Попробуйте сами
<?php
// Подключите файлы инструментов
require_once 'Guitar.php';
require_once 'Drum.php';
// Чтение входных данных
$guitarName = trim(fgets(STDIN));
$drumName = trim(fgets(STDIN));
// TODO: Создайте функцию performWith, которая:
// - Принимает параметр Instrument (используйте подсказку типа: Instrument $instrument)
// - Возвращает результат вызова play() на инструменте
// TODO: Создайте Guitar с $guitarName и Drum с $drumName
// TODO: Передайте каждый в performWith() и выведите результаты (сначала гитару, затем барабан)
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово $thisМетодыСвойстваКонструктор (__construct)Деструктор (__destruct)Итоги — Простой калькулятор4Наследование
Основы наследованияКлючевое слово parent::Переопределение методовКлючевое слово finalАбстрактные классыИтоги — Иерархия сотрудников7Инкапсуляция
Public, Protected, PrivateПодробный разбор модификаторов доступаГеттеры и сеттерыСокрытие данныхConstructor Promotion (8.0)Итоги — Система учета студентов10Продвинутые концепции ООП
Композиция против наследованияВнедрение зависимостейАнонимные классыПеречисления (PHP 8.1)Файберы (PHP 8.1)Глубокое погружение в клонирование объектовГенераторы и итераторы13Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий2Пространства имен и автозагрузка
Введение в пространства именКлючевое слово useСтандарт автозагрузки PSR-4Автозагрузчик ComposerИтоги: структурированный проект5Интерфейсы и контракты
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовИнтерфейс против абстрактного классаType Hinting с интерфейсамиИтоги — Калькулятор фигур8Магические методы
Введение в магические методы__toString и __debugInfo__get, __set, __isset, __unset__call и __callStatic__clone и клонирование объектов__serialize и __unserializeИтоги — Кастомная коллекция11Система типов и обработка ошибок
Объявление типовNullable-типыТипы объединения и пересеченияКлассы исключенийИерархия пользовательских исключенийTry, Catch, FinallyИтоги — Валидатор форм14Проект: Управление библиотекой
Обзор проектаКлассы Book и User3Свойства классов
Свойства экземпляра и статические свойстваКонстанты в классахСтатические методы и свойстваПриватные и защищенные свойстваСвойства Readonly (PHP 8.1)Итоги — Менеджер банковского счета6Полиморфизм
Снова о переопределении методовПолиморфизм через интерфейсыType Hinting и Union TypesПозднее статическое связываниеИтоги — Payment Processor9Трейты
Введение в трейтыИспользование нескольких трейтовРазрешение конфликтов трейтовАбстрактные методы в трейтахТрейты и наследование12Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy