Menu
CoddyTech

Từ khóa final

Thuộc phần Lập trình hướng đối tượng trong hành trình PHP của Coddy. Bài học 24 trên 91.

Kế thừa và ghi đè phương thức mang lại sự linh hoạt, nhưng đôi khi bạn cần ngăn một số lớp hoặc phương thức bị thay đổi. Từ khóa final khóa chặt code, đảm bảo các cách triển khai cụ thể không thể bị lớp con thay đổi.

Khi bạn đánh dấu một phương thức là final, không lớp con nào có thể ghi đè phương thức đó:

<?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();

Đầu ra:

ACC-1

Không thể ghi đè phương thức getAccountId() trong SavingsAccount hoặc bất kỳ lớp con nào khác. Điều này bảo vệ chức năng quan trọng cần giữ nhất quán giữa tất cả các loại tài khoản.

Bạn cũng có thể đánh dấu toàn bộ một lớp là final để ngăn mọi kế thừa:

<?php
final class SecurityManager {
    public function authenticate($user) {
        return "Authenticating $user";
    }
}

$security = new SecurityManager();
echo $security->authenticate("admin");

Đầu ra:

Authenticating admin

Không lớp nào có thể kế thừa SecurityManager. Điều này hữu ích với các lớp nhạy cảm về bảo mật hoặc khi thiết kế lớp đã hoàn chỉnh và không nên sửa đổi.

Điểm chính: Dùng final cho các phương thức để ngăn ghi đè nhưng vẫn cho phép kế thừa, hoặc dùng cho các lớp để ngăn kế thừa hoàn toàn. Đây là công cụ giúp bảo vệ đoạn code quan trọng, vốn phải hoạt động chính xác như thiết kế.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống quản lý tài liệu để minh họa cách từ khóa final bảo vệ chức năng quan trọng khỏi bị các lớp con sửa đổi.

Bạn sẽ tạo ba tệp phối hợp với nhau để quản lý các loại tài liệu khác nhau, đồng thời giữ nguyên một số tính năng bảo mật:

  • Document.php: Định nghĩa lớp Document làm lớp cơ sở cho mọi tài liệu. Lớp này cần có thuộc tính công khai $title và thuộc tính bảo vệ $author. Hàm khởi tạo nhận cả tiêu đề và tác giả. Thêm một phương thức final có tên getSignature(), trả về "Signed by: [author]". Các lớp con không được thay đổi tính năng bảo mật này. Đồng thời, thêm phương thức thông thường getContent(), trả về "Document: [title]".
  • Report.php: Định nghĩa lớp Report kế thừa Document. Thêm tệp Document ở đầu tệp. Lớp này bổ sung thuộc tính $department. Hàm khởi tạo cần nhận tiêu đề, tác giả và phòng ban: dùng parent::__construct() cho hai giá trị đầu, sau đó gán phòng ban. Ghi đè phương thức getContent() để trả về "Report: [title] ([department])". Lớp Report kế thừa phương thức getSignature() có từ khóa final mà không thể thay đổi phương thức này.
  • main.php: Thêm tệp Report. Bạn sẽ nhận ba đầu vào: tiêu đề tài liệu, tên tác giả và phòng ban. Tạo một đối tượng Report với các giá trị này. In kết quả của getContent() ở dòng đầu tiên, sau đó in kết quả của getSignature() ở dòng thứ hai.

Thử thách này cho thấy các phương thức final bảo vệ chức năng quan trọng như thế nào: việc tạo chữ ký luôn nhất quán với mọi loại tài liệu, trong khi mỗi lớp con có thể tùy chỉnh các phương thức khác như getContent(). Lớp Report có thể thay đổi cách hiển thị nội dung, nhưng lớp cha khóa định dạng chữ ký.

Tự làm thử

<?php
require_once 'Report.php';

// Đọc đầu vào
$title = trim(fgets(STDIN));
$author = trim(fgets(STDIN));
$department = trim(fgets(STDIN));

// TODO: Tạo đối tượng Report bằng các giá trị đầu vào

// TODO: In ra kết quả của getContent()

// TODO: In ra kết quả của getSignature()
?>
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch PHP online