Sửa lỗi PHP Fatal Error: Khai báo phương thức không tương thích

intermediate🐘 PHP2026-06-27| PHP 7.x, PHP 8.x, mọi hệ điều hành (Linux, Windows, macOS) sử dụng lập trình hướng đối tượng.

Error Message

Fatal error: Declaration of ChildClass::methodName($arg) must be compatible with ParentClass::methodName($arg)
#php#oop#debugging#backend

Phân Tích Lỗi

Chắc hẳn ai cũng đã từng gặp tình huống này: bạn deploy một bản cập nhật nhỏ, tải lại trang, rồi đối mặt với cái gọi là "Màn Hình Trắng Chết Chóc". Khi kiểm tra error log, bạn thấy một fatal error phàn nàn về tính tương thích của phương thức. Điều này xảy ra vì PHP thực thi rất nghiêm ngặt các quy tắc kế thừa.

Fatal error: Declaration of ChildClass::methodName($arg) must be compatible with ParentClass::methodName($arg)

Nguyên Nhân Gốc Rễ

Hãy nghĩ về kế thừa như một hợp đồng pháp lý. Nếu class cha hứa rằng một phương thức nhận vào một string, thì class con không thể tự nhiên đòi nhận một array. Nếu làm vậy, bất kỳ đoạn code nào được thiết kế để làm việc với class cha sẽ bị lỗi khi nhận class con. Khái niệm này được gọi là Nguyên tắc Thay thế Liskov.

PHP ném ra lỗi này trong giai đoạn biên dịch. Nó xảy ra ngay khi engine phát hiện một phương thức của lớp con có chữ ký khác với định nghĩa trong class cha hoặc interface. Điều này ngăn ứng dụng của bạn bị crash sau này trong quá trình thực thi.

Các Tình Huống Thường Gặp và Giải Pháp

1. Thêm Tham Số Bắt Buộc

Đây là thủ phạm phổ biến nhất. Bạn cần thêm dữ liệu trong một lớp con, nên bạn thêm một tham số mới vào phương thức. Tuy nhiên, nếu tham số đó không có trong class cha, "hợp đồng" sẽ bị vi phạm.

Vấn đề:

class FileUploader {
    public function upload($file) { /* ... */ }
}

class S3Uploader extends FileUploader {
    // Lỗi vì $bucket là bắt buộc nhưng không tồn tại trong class cha
    public function upload($file, $bucket) { /* ... */ }
}

Giải pháp: Đặt giá trị mặc định cho tham số mới. Bằng cách làm cho nó tùy chọn, phương thức của lớp con vẫn tương thích với kỳ vọng một tham số của class cha.

class S3Uploader extends FileUploader {
    // Thêm giá trị mặc định (null hoặc chuỗi rỗng) để khắc phục sự không tương thích
    public function upload($file, $bucket = 'default-vault') { /* ... */ }
}

2. Không Khớp Type Hint và Nullability

Từ PHP 7.1, nullability (dùng tiền tố ?) đã trở thành nguồn gốc phổ biến của các lỗi này. Nếu phương thức cha cho phép giá trị null nhưng class con thì không, hoặc ngược lại, PHP sẽ dừng quá trình xử lý.

Vấn đề:

class UserProfile {
    public function update(?string $bio) { /* ... */ }
}

class AdminProfile extends UserProfile {
    // Lỗi: Class con đã xóa '?' khiến nó chặt chẽ hơn class cha
    public function update(string $bio) { /* ... */ }
}

Giải pháp: Khớp chính xác các type hint. Nếu class cha dùng ?string, class con cũng phải dùng ?string để duy trì interface.

3. Kiểu Trả Về Không Nhất Quán

Kiểu trả về được thực thi nghiêm ngặt từ PHP 7.0. Nếu một phương thức cha chỉ định trả về kiểu int, class con không thể trả về float hay string.

Vấn đề:

interface CacheProvider {
    public function get(string $key): array;
}

class RedisCache implements CacheProvider {
    // Lỗi: Thiếu kiểu trả về hoặc trả về kiểu khác
    public function get(string $key) { return 'data'; }
}

Giải pháp: Khai báo rõ ràng kiểu trả về trong class con để khớp với interface.

class RedisCache implements CacheProvider {
    public function get(string $key): array { 
        return ['data']; 
    }
}

PHP Hiện Đại: Covariance và Contravariance

Nếu bạn đang dùng PHP 8.0 trở lên, các quy tắc linh hoạt hơn một chút nhờ Variance. Bạn có thể dùng kiểu ít cụ thể hơn cho tham số (Contravariance) hoặc kiểu cụ thể hơn cho giá trị trả về (Covariance).

- **Parameter Contravariance:** Class con có thể nhận `mixed` nếu class cha nhận `string`.
- **Return Type Covariance:** Class con có thể trả về object `User` nếu class cha trả về `BaseModel` tổng quát.

Nếu các tính năng này không hoạt động, hãy kiểm tra php -v. Những cải tiến này chỉ hoàn thiện đầy đủ từ phiên bản 8.0.

Cách Xác Minh Bản Sửa Lỗi

Đừng phụ thuộc vào việc tự tay tải lại trình duyệt. Dùng các công cụ sau để phát hiện lỗi trong vài giây:

- **Lint trên Terminal:** Chạy `php -l path/to/file.php`. Lệnh này kiểm tra cú pháp mà không thực thi code.
- **Phân tích tĩnh:** Các công cụ như PHPStan hoặc Psalm là cứu cánh thực sự. Chạy `vendor/bin/phpstan analyse` có thể tìm thấy các sự không khớp này trên 1.000+ file trong vòng chưa đến 10 giây.
- **Sao chép chữ ký phương thức:** Khi không chắc chắn, hãy sao chép dòng khai báo phương thức từ class cha và dán trực tiếp vào class con.

Mẹo Hay Để Phòng Tránh

- **Để IDE làm việc thay bạn:** Dùng PhpStorm hoặc VS Code với extension Intelephense. Chúng sẽ đánh dấu các sự không khớp bằng chữ đỏ trước khi bạn kịp lưu file.
- **Ngoại lệ Constructor:** Hãy nhớ rằng `__construct` là trường hợp đặc biệt. Bạn có thể tự do thay đổi tham số constructor trong class con mà không kích hoạt fatal error cụ thể này.
- **Ưu tiên Composition hơn Inheritance:** Nếu bạn liên tục phải vật lộn với chữ ký phương thức, đó là dấu hiệu cần chú ý. Có thể bạn nên dùng composition thay vì kế thừa một class không hoàn toàn phù hợp với nhu cầu của mình.

Related Error Notes