Menu
Coddy logo textTech

Ключевое слово 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 для методов, чтобы предотвратить переопределение, сохраняя при этом возможность наследования, или для классов, чтобы полностью запретить наследование. Это инструмент для защиты критически важного кода, который должен работать именно так, как было задумано.

challenge icon

Задание

Легко

Давайте создадим систему управления документами, которая демонстрирует, как ключевое слово 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()
?>
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование