Ключевое слово final
Часть раздела Объектно-ориентированное программирование путешествия по PHP на Coddy — урок 24 из 91.
Хотя наследование и переопределение методов обеспечивают гибкость, иногда необходимо предотвратить изменение определенных классов или методов. Ключевое слово final блокирует ваш код, гарантируя, что конкретные реализации не смогут быть изменены дочерними классами.
Когда вы помечаете метод как final, ни один дочерний класс не может его переопределить:
<?php
class BankAccount {
protected $balance;
public function __construct($balance) {
$this->balance = $balance;
}
final public function getAccountId() {
return "ACC-" . spl_object_id($this);
}
}
class SavingsAccount extends BankAccount {
public function addInterest() {
return $this->balance * 0.05;
}
}
$account = new SavingsAccount(1000);
echo $account->getAccountId();
Вывод:
ACC-1Метод getAccountId() не может быть переопределен в SavingsAccount или любом другом дочернем классе. Это защищает критически важную функциональность, которая должна оставаться неизменной для всех типов аккаунтов.
Вы также можете пометить весь класс как final, чтобы предотвратить любое наследование:
<?php
final class SecurityManager {
public function authenticate($user) {
return "Authenticating $user";
}
}
$security = new SecurityManager();
echo $security->authenticate("admin");
Вывод:
Authenticating adminНи один класс не может расширять SecurityManager. Это полезно для классов, чувствительных к безопасности, или когда проектирование класса завершено и он не должен изменяться.
Ключевой момент: Используйте final для методов, чтобы предотвратить переопределение, сохраняя при этом возможность наследования, или для классов, чтобы полностью запретить наследование. Это инструмент для защиты критически важного кода, который должен работать именно так, как было задумано.
Задание
ЛегкоДавайте создадим систему управления документами, которая демонстрирует, как ключевое слово final защищает критически важную функциональность от изменения дочерними классами.
Вы создадите три файла, которые работают вместе для управления различными типами документов, гарантируя при этом, что определенные функции безопасности остаются заблокированными:
Document.php— Определите классDocument, который служит базой для всех документов. Он должен иметь публичное свойство$titleи защищенное свойство$author. Конструктор принимает и заголовок, и автора. Включите методfinalс именемgetSignature(), который возвращает"Signed by: ", за которым следует имя автора — эта функция безопасности никогда не должна изменяться дочерними классами. Также добавьте обычный методgetContent(), который возвращает"Document: ", за которым следует заголовок.Report.php— Определите классReport, который расширяетDocument. Подключите файл Document в начале. Этот класс добавляет свойство$department. Конструктор должен принимать заголовок, автора и отдел — используйтеparent::__construct()для первых двух, затем установите отдел. Переопределите методgetContent(), чтобы он возвращал"Report: [title] ([department])"(используя соответствующие значения). КлассReportнаследует финальный методgetSignature()без возможности его изменить.main.php— Подключите файл Report. Вы получите три входных значения: заголовок документа, имя автора и отдел. Создайте объектReportс этими значениями. Выведите результатgetContent()на первой строке, затем выведите результатgetSignature()на второй строке.
Эта задача показывает, как методы final защищают критически важную функциональность — генерация подписи остается неизменной для всех типов документов, в то время как другие методы, такие как getContent(), могут быть настроены каждым дочерним классом. Report может изменить способ отображения контента, но формат подписи заблокирован в родительском классе.
Шпаргалка
Ключевое слово final предотвращает изменение классов или методов дочерними классами.
Финальные методы: Пометьте метод как final, чтобы предотвратить его переопределение дочерними классами:
<?php
class BankAccount {
protected $balance;
final public function getAccountId() {
return "ACC-" . spl_object_id($this);
}
}
class SavingsAccount extends BankAccount {
// Невозможно переопределить getAccountId()
}
Финальные классы: Пометьте весь класс как final, чтобы предотвратить любое наследование:
<?php
final class SecurityManager {
public function authenticate($user) {
return "Authenticating $user";
}
}
// Ни один класс не может наследоваться от SecurityManager
Используйте final для методов, чтобы защитить определенную функциональность, разрешая при этом наследование, или для классов, чтобы полностью запретить наследование. Это полезно для кода, чувствительного к безопасности, или когда реализации должны оставаться неизменными.
Попробуйте сами
<?php
require_once 'Report.php';
// Чтение входных данных
$title = trim(fgets(STDIN));
$author = trim(fgets(STDIN));
$department = trim(fgets(STDIN));
// TODO: Создать объект Report с входными значениями
// TODO: Вывести результат getContent()
// TODO: Вывести результат getSignature()
?>В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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