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 apithực hiện IHttpApivà một đối tượng đang configthự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 SpecificConfigthực hiện IConfignhư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::frobnicatecó một SpecificConfignơ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 Tcó 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 Tcó 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 __constructtrong 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.