Mari kita abaikan sejenak bahwa metode yang dimaksud adalah __constructdan menyebutnya frobnicate. Sekarang anggaplah Anda memiliki objek apipelaksana IHttpApi, dan configpelaksana objek IHttpConfig. Jelas, kode ini sesuai dengan antarmuka:
$api->frobnicate($config)
Tapi mari kita misalkan kita upcast apiuntuk IApi, misalnya lewat itu untuk function frobnicateTwice(IApi $api). Sekarang dalam fungsi itu, frobnicatedipanggil, dan karena itu hanya berurusan dengan IApi, itu dapat melakukan panggilan seperti di $api->frobnicate(new SpecificConfig(...))mana SpecificConfigmengimplementasikan IConfigtetapi tidak IHttpConfig. Tidak ada seorangpun yang melakukan sesuatu yang tidak menyenangkan dengan tipe, tetapi IHttpApi::frobnicatemendapat SpecificConfigtempat yang diharapkan a IHttpConfig.
Ini tidak baik. Kami tidak ingin melarang upcasting, kami ingin subtyping, dan kami jelas ingin beberapa kelas mengimplementasikan antarmuka. Jadi satu-satunya pilihan yang masuk akal adalah melarang metode subtipe yang membutuhkan jenis parameter yang lebih spesifik . (Masalah serupa terjadi ketika Anda ingin mengembalikan jenis yang lebih umum .)
Secara formal, Anda telah memasuki jebakan klasik seputar polimorfisme, varian . Tidak semua kemunculan jenis Tdapat diganti dengan subtipe U. Sebaliknya, tidak semua kemunculan suatu tipe Tdapat digantikan oleh supertype S . Pertimbangan yang cermat (atau lebih baik lagi, penerapan teori jenis yang ketat) diperlukan.
Kembali ke __construct: Karena AFAIK Anda tidak dapat membuat instance antarmuka secara tepat, hanya implementer konkret, ini mungkin tampak seperti pembatasan tanpa tujuan (tidak akan pernah dipanggil melalui antarmuka). Tetapi dalam kasus itu, mengapa termasuk __constructdalam antarmuka untuk memulai? Bagaimanapun, itu akan sedikit berguna untuk kasus khusus di __constructsini.