2010-12-30 28 views
13

Tôi nghĩ rằng sẽ dễ dàng hơn nhiều khi thấy vấn đề trong ví dụ mã hơn là viết câu hỏi ngay từ đầu. Đây là mã php của tôi:Php loại gợi ý không nhận được cùng với các giao diện và các lớp trừu tượng?

<?php 

interface AnInterface 
{ 
     public function method(); 
}  

class AClass implements AnInterface 
{ 
     public function method() 
     { 
       echo __METHOD__; 
     } 
}  

abstract class AnAbstractClass 
{ 
     abstract public function method(AnInterface $Object); 
} 

class ConcreteClass extends AnAbstractClass 
{ 
     public function method(AClass $Object) 
     { 
       $Object->method(); 
     } 
} 

$Object1 = new ConcreteClass(); 
$Object2 = new AClass(); 

$Object1->method($Object2); 

Đoạn mã trên gây ra các lỗi sau:

Fatal error: Declaration of ConcreteClass::method() must be compatible with that of AnAbstractClass::method()

Vấn đề là php dường như không được công nhận chữ ký của AnAbstractClass :: phương pháp và ConcreteClass: : phương pháp tương thích. Tôi có làm điều gì sai? Cảm ơn!

+4

Xin vui lòng, * vui lòng * tham gia vào thói quen đăng thông báo lỗi mà mã của bạn đang tạo. Đăng mã mà không đăng đầu ra (hoặc lỗi) là vô dụng. – meagar

Trả lời

24

php doesn't seem to be recognizing the signatures of AnAbstractClass::method and ConcreteClass::method as compatible.

PHP đúng, chúng là không tương thích. Bằng cách chỉ cho phép các trường hợp AClass (hoặc con của nó) được chuyển đến ConcreteClass::method, bạn vi phạm hợp đồng mà AnAbstractClass cung cấp: Bất kỳ lớp con nào của nó phải chấp nhận AnInterface làm đối số cho số method().

Nếu ví dụ bạn làm việc, và tôi đã có một lớp BClass thực hiện AnInterface, chúng tôi muốn có một tình huống mà theo AnAbstractClass, method() nên chấp nhận trường hợp của BClass, trong khi theo ConcreteClass, nó không nên.

Thay đổi chữ ký của bạn cho ConcreteClass::method để khớp với chữ ký của AnAbstractClass::method.

+3

Sau khi cho nó một số suy nghĩ tôi đi đến kết luận rằng bạn là đúng. Tôi tin rằng tôi đã cố gắng để bỏ lỡ một mô hình. Cảm ơn nhiều. – Muc

+0

tôi có thể ghi đè lên nó trong phpdoc để tự động hoàn thành trong IDE của tôi (phpStorm)? Bởi vì bây giờ nó không cho tôi khả năng đó – Crusader

2

Không tính toán. Chúng tôi đã có cuộc thảo luận tương tự hôm qua:
Can parameter types be specialized in PHP

Tất cả các lớp dẫn xuất của bạn phải triển khai chữ ký phương thức giống hệt nhau.

Đây là điều lý tưởng nên được kiểm tra khi chạy. Nhưng trong PHP, trình phân tích cú pháp thực hiện. (. Để bù đắp, PHP không kiểm tra quyền truy cập thuộc tính private/bảo vệ lúc phân tích cú pháp, nhưng để điều đó một thay thổi lên trong thời gian chạy)

Nếu bạn muốn thực thi một loại nghiêm ngặt hơn, tôi sẽ tư vấn cho:

assert(is_a($Object, "AClass")); 
+5

Cho rằng đó là PHP 5, xác nhận đó nên đọc 'assert ($ Object instanceof AClass);' – BoltClock

+0

Vâng, điều đó có thể hoạt động, nhưng thực sự nó không phải là cách nó được cho là, tôi nghĩ rằng tôi đã có một quan niệm sai lầm ở nơi đầu tiên , xem câu trả lời từ @meagar – Muc

+0

Các trường hợp như kế thừa từ ArrayObject ISTM sẽ là ứng cử viên tốt để thực hiện xác nhận loại hoặc ném nếu loại sai đã được nhận. Nhưng bạn không thể thay đổi giao diện cơ bản (ví dụ: ArrayAccess :: offsetSet luôn lấy thông số hỗn hợp cho giá trị). –

2

Dưới đây là một ví dụ cho thấy, tại sao điều này là không được phép:

<?php 
class BClass implements AnInterface { } 

function moo(AnAbstractClass $abstract) 
{ 
    $b = new BClass(); 
    $abstract->method($b); 
} 

Đây sẽ là một mã hợp lệ, nhưng nó sẽ thất bại, nếu bạn vượt qua một ConcreteClass để Moo, bởi vì phương pháp của nó ConcreteClass::method không cho phép BClass.

Rất phức tạp, nhưng sẽ dễ hiểu hơn nếu bạn thấy ví dụ.

Các vấn đề liên quan