Переопределение методов
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 23 из 91.
Иногда унаследованный метод родительского класса не совсем подходит для нужд дочернего класса. Переопределение методов (Method overriding) позволяет дочернему классу предоставить собственную реализацию метода, который уже существует в родительском классе.
Чтобы переопределить метод, просто определите метод в дочернем классе с тем же именем, что и метод родительского класса:
<?php
class Animal {
public $name;
public function __construct($name) {
$this->name = $name;
}
public function speak() {
return "$this->name makes a sound";
}
}
class Cat extends Animal {
public function speak() {
return "$this->name says meow";
}
}
$cat = new Cat("Whiskers");
echo $cat->speak();
Вывод:
Whiskers says meowКласс Cat полностью заменяет родительский метод speak() своей собственной версией. Когда вы вызываете speak() у объекта cat, PHP использует реализацию дочернего класса.
Вы также можете расширить поведение родительского класса, комбинируя parent:: с вашей собственной логикой:
<?php
class Dog extends Animal {
public function speak() {
return parent::speak() . " - woof woof!";
}
}
$dog = new Dog("Rex");
echo $dog->speak();
Вывод:
Rex makes a sound - woof woof!Ключевой момент: Переопределение методов позволяет дочерним классам настраивать унаследованное поведение. Вы можете полностью заменить метод или использовать parent::, чтобы дополнить оригинальную реализацию.
Задание
ЛегкоДавайте создадим систему уведомлений, которая демонстрирует, как дочерние классы могут полностью заменять или расширять методы родительских классов с помощью переопределения методов.
Вы создадите три файла, которые работают вместе для отправки различных типов уведомлений, каждый из которых обладает своим уникальным поведением:
Notification.php— Определите классNotification, который служит базой для всех типов уведомлений. Он должен иметь публичное свойство$recipientи конструктор, который принимает и устанавливает получателя. Включите методsend($message), который возвращает"Sending to $this->recipient: $message".UrgentNotification.php— Определите классUrgentNotification, который расширяетNotification. Подключите файл Notification в начале. Этот класс должен полностью переопределить методsend($message), чтобы он возвращал"URGENT to $this->recipient: $message!!!"— обратите внимание на префикс "URGENT" и восклицательные знаки в конце. Это демонстрирует полную замену поведения родителя.LoggedNotification.php— Определите классLoggedNotification, который расширяетNotification. Подключите файл Notification в начале. Этот класс должен переопределитьsend($message), но основываться на реализации родителя: вызовитеparent::send($message)и добавьте" [logged]"к результату. Это демонстрирует расширение, а не замену поведения.
В main.php подключите все три файла классов уведомлений. Вы получите два входных значения: имя получателя и сообщение для отправки. Создайте по одному экземпляру каждого типа уведомления (все используют одного и того же получателя), затем вызовите send() с сообщением для каждого из них. Выведите каждый результат на отдельной строке в следующем порядке: обычное уведомление, срочное уведомление, а затем логируемое уведомление.
Эта задача показывает оба подхода к переопределению методов — UrgentNotification полностью заменяет логику родителя своим собственным форматированием, в то время как LoggedNotification использует parent::, чтобы сохранить исходное поведение и дополнить его.
Шпаргалка
Переопределение методов позволяет дочернему классу предоставить собственную реализацию метода, унаследованного от родительского класса.
Чтобы переопределить метод, определите в дочернем классе метод с тем же именем, что и метод родителя:
<?php
class Animal {
public function speak() {
return "makes a sound";
}
}
class Cat extends Animal {
public function speak() {
return "says meow";
}
}
Дочерний класс полностью заменяет реализацию метода родителя. При вызове для дочернего объекта PHP использует версию дочернего класса.
Чтобы расширить поведение родителя вместо его замены, используйте parent:: для вызова родительского метода и добавьте свою собственную логику:
<?php
class Dog extends Animal {
public function speak() {
return parent::speak() . " - woof woof!";
}
}
Это объединяет исходное поведение родителя с дополнительной функциональностью дочернего класса.
Попробуйте сами
<?php
require_once 'Notification.php';
require_once 'UrgentNotification.php';
require_once 'LoggedNotification.php';
// Чтение входных данных
$recipient = trim(fgets(STDIN));
$message = trim(fgets(STDIN));
// TODO: Создать по одному экземпляру каждого типа уведомления (все используют одного и того же получателя)
// TODO: Вызвать метод send() с сообщением для каждого уведомления
// Вывести каждый результат на отдельной строке в следующем порядке:
// 1. Обычное уведомление
// 2. Срочное уведомление
// 3. Логируемое уведомление
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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