Menu
CoddyTech

Giải quyết xung đột giữa các đặc tính

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 53 trên 91.

Khi hai trait định nghĩa các phương thức trùng tên, PHP sẽ báo lỗi nghiêm trọng. Bạn phải chỉ rõ cho PHP cách xử lý xung đột này bằng các toán tử insteadof và as.

<?php
trait FileLogger {
    public function log(string $message): void {
        echo "File: $message";
    }
}

trait DatabaseLogger {
    public function log(string $message): void {
        echo "DB: $message";
    }
}

class Application {
    use FileLogger, DatabaseLogger {
        FileLogger::log insteadof DatabaseLogger;
        DatabaseLogger::log as logToDatabase;
    }
}

$app = new Application();
$app->log("Error occurred");
$app->logToDatabase("Error occurred");

Đầu ra:

File: Error occurred
DB: Error occurred

Toán tử insteadof chọn phương thức của trait nào sẽ được dùng khi có xung đột. Trong ví dụ này, FileLogger::log được chọn và trở thành phương thức log() mặc định. Toán tử as tạo bí danh, cho phép bạn truy cập phương thức của trait còn lại bằng một tên khác.

Bạn cũng có thể dùng as để thay đổi phạm vi hiển thị của một phương thức:

<?php
trait Greeting {
    public function sayHello(): void {
        echo "Hello!";
    }
}

class Person {
    use Greeting {
        sayHello as private;
    }
}

Điều này khiến sayHello() chỉ có thể được truy cập riêng trong lớp Person, dù phương thức này là công khai trong trait. Cách giải quyết xung đột giúp bạn kiểm soát chi tiết cách các phương thức của trait tích hợp vào lớp.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống thông báo, trong đó các kênh khác nhau có thể gửi tin nhắn, nhưng chúng ta cần giải quyết xung đột khi nhiều trait cung cấp phương thức cùng tên.

Bạn sẽ sắp xếp code trong bốn tệp:

  • EmailNotifier.php: Tạo một trait có tên EmailNotifier với phương thức notify(string $message) trả về "Email: [message]".
  • SmsNotifier.php: Tạo một trait có tên SmsNotifier với phương thức notify(string $message) trả về "SMS: [message]".
  • AlertService.php: Tạo lớp AlertService sử dụng cả hai trait. Vì cả hai trait đều có phương thức notify(), bạn cần giải quyết xung đột này:
    • Dùng EmailNotifier::notify làm phương thức notify() mặc định
    • Tạo bí danh notifyBySms cho phương thức SmsNotifier::notify
    Đồng thời, thêm phương thức notifyAll(string $message) gọi cả hai phương thức thông báo và trả về kết quả của chúng trên các dòng riêng biệt.
  • main.php: Nạp tất cả các tệp cần thiết và tạo một đối tượng AlertService. Bạn sẽ nhận một đầu vào: một chuỗi tin nhắn. In ra ba dòng:
    • Kết quả gọi notify() với tin nhắn đó
    • Kết quả gọi notifyBySms() với tin nhắn đó
    • Kết quả gọi notifyAll() với tin nhắn đó

Ví dụ này minh họa cách insteadof xác định phương thức của trait nào sẽ được dùng khi xảy ra xung đột tên, còn as cho phép bạn tiếp tục dùng phương thức của trait còn lại dưới một tên khác.

Tự làm thử

<?php
require_once 'AlertService.php';

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

// TODO: Tạo một instance của AlertService

// TODO: In ra kết quả khi gọi notify() với thông điệp

// TODO: In ra kết quả khi gọi notifyBySms() với thông điệp

// TODO: In ra kết quả khi gọi notifyAll() với thông điệp
?>
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