Chúng ta hãy bỏ qua một giây rằng phương thức đang nói __construct
đến và gọi nó frobnicate
. Bây giờ giả sử bạn có một đối tượng đang api
thực hiện IHttpApi
và một đối tượng đang config
thực hiện IHttpConfig
. Rõ ràng, mã này phù hợp với giao diện:
$api->frobnicate($config)
Nhưng chúng ta hãy giả sử chúng ta bị ném lên trời api
để IApi
, ví dụ đi qua nó để function frobnicateTwice(IApi $api)
. Bây giờ trong chức năng đó, frobnicate
được gọi và vì nó chỉ xử lý IApi
, nên nó có thể thực hiện một cuộc gọi như $api->frobnicate(new SpecificConfig(...))
nơi SpecificConfig
thực hiện IConfig
nhưng không IHttpConfig
. Không có ai làm bất cứ điều gì không hợp lý với các loại, nhưng vẫn IHttpApi::frobnicate
có một SpecificConfig
nơi mà nó mong đợi a IHttpConfig
.
Điều này là không tốt. Chúng tôi không muốn cấm upcasting, chúng tôi muốn phân nhóm và rõ ràng chúng tôi muốn nhiều lớp thực hiện một giao diện. Vì vậy, tùy chọn hợp lý duy nhất là cấm một phương thức kiểu con yêu cầu các loại cụ thể hơn cho các tham số. (Một vấn đề tương tự xảy ra khi bạn muốn trả về một loại tổng quát hơn .)
Chính thức, bạn đã bước vào một cái bẫy cổ điển xung quanh tính đa hình, phương sai . Không phải tất cả các lần xuất hiện của một loại T
có thể được thay thế bằng một kiểu con U
. Ngược lại, không phải tất cả các lần xuất hiện của một loại T
có thể được thay thế bằng một siêu kiểu S
. Cần xem xét cẩn thận (hoặc tốt hơn nữa, áp dụng nghiêm ngặt lý thuyết loại).
Quay trở lại __construct
: Vì AFAIK bạn không thể khởi tạo chính xác một giao diện, chỉ có một người triển khai cụ thể, điều này có vẻ như là một hạn chế vô nghĩa (sẽ không bao giờ được gọi thông qua giao diện). Nhưng trong trường hợp đó, tại sao lại bao gồm __construct
trong giao diện để bắt đầu? Bất kể, nó sẽ ít được sử dụng cho trường hợp đặc biệt __construct
ở đây.