PHP'de Yasadışı: OOP tasarım nedeni var mı?


16

Aşağıdaki arayüz kalıtımı PHP'de yasadışıdır, ancak gerçek hayatta oldukça yararlı olacağını düşünüyorum. Aşağıdaki tasarımda gerçek bir antipattern veya belgelenmiş bir problem var mı, PHP'nin beni koruyor mu?

<?php

/**
 * Marker interface
 */
interface IConfig {}

/**
 * An api sdk tool
 */
interface IApi
{
    public __construct(IConfig $cfg);
}

/**
 * Api configuration specific to http
 */
interface IHttpConfig extends IConfig
{
    public getSomeNiceHttpSpecificFeature();
}

/**
 * Illegal, but would be really nice to have.
 * Is this not allowed by design?
 */
interface IHttpApi extends IApi
{
    /**
     * This constructor must have -exactly- the same
     * signature as IApi, even though its first argument
     * is a subtype of the parent interface's required
     * constructor parameter.
     */
    public __construct(IHttpConfig $cfg);

}

Yanıtlar:


22

En Söz konusu yöntem bir saniye görmezden edelim __constructve diyoruz frobnicate. Şimdi bir nesne apiuygulamanız IHttpApive bir nesne configuygulamanız olduğunu varsayalım IHttpConfig. Açıkçası, bu kod arayüze uyar:

$api->frobnicate($config)

Ama yukarıya bakan biz varsayalım apiiçin IApigeçirmeden örneğin function frobnicateTwice(IApi $api). Şimdi bu işlevinde, frobnicatedenir ve sadece ilgilenir beri IApi, bu gibi bir çağrı yapabilir $api->frobnicate(new SpecificConfig(...))nerede SpecificConfiguygular IConfigancak IHttpConfig. Hiçbir noktada kimse türleri ile çirkin bir şey yaptığını, henüz IHttpApi::frobnicatebir var SpecificConfigbir bekledikleri yerden IHttpConfig.

Bu iyi değil. Geçişi yasaklamak istemiyoruz, alt tipleme istiyoruz ve açıkça bir arayüz uygulamak için birden fazla sınıf istiyoruz. Bu yüzden tek mantıklı seçenek, parametreler için daha spesifik tipler gerektiren bir alt tip yöntemini yasaklamaktır . ( Daha genel bir tür döndürmek istediğinizde de benzer bir sorun ortaya çıkar .)

Resmi olarak, polimorfizm, varyans çevreleyen klasik bir tuzağa girdiniz . Bir türün Ttüm örneklerinin yerine bir alt tür geçemez U. Tersine, bir tür değil tüm olaylar Tbir yerini büyük olabilir süpertip S . Dikkatli düşünmek (ya da daha iyisi, tip teorisinin sıkı bir şekilde uygulanması) gereklidir.

Geri dönüyorum __construct: AFAIK bir arayüzü, sadece somut bir uygulayıcıyı tam olarak başlatamadığınız için, bu anlamsız bir kısıtlama gibi görünebilir (asla bir arayüzden çağrılmayacaktır). Ama bu durumda, neden __constructbaşlangıçta arayüze dahil edelim? Ne olursa olsun, __constructburada özel durum için çok az faydası olacaktır .


19

Evet, bu doğrudan Liskov İkame İlkesinden (LSP) gelir . Bir yöntemi geçersiz kıldığınızda, dönüş türü daha belirgin hale gelirken, argüman türlerinin aynı kalması veya daha genel hale gelmesi gerekir.

Bu, dışındaki yöntemlerle daha belirgindir __construct. Düşünmek:

class Vehicle {}
class Car extends Vehicle {}
class Motorcycle extends Vehicle {}

class Driver {
    public drive(Vehicle $v) { ... }
}
class CarDriver extends Driver {
    public drive(Car $c) { ... }
}

A CarDriverbir olan Driverbir nedenle, CarDriverörneğin yapmak gerekir şey bir o Driverkutunun. Sürüş dahil Motorcycles, çünkü bu sadece bir Vehicle. Ancak argüman türü, drivea'nın CarDriversadece Cars - bir çelişki CarDriver sürdürebileceğini söylüyor : uygun bir alt sınıf olamazDriver .

Tersi daha mantıklı:

class CarDriver {
    public drive(Car $c) { ... }
}
class MultiTalentedDriver extends CarDriver {
    public drive(Vehicle $v) { ... }
}

A CarDriveryalnızca Cars kullanabilir. A MultiTalentedDriverda Cars'yi kullanabilir, çünkü a Carsadece bir Vehicle. Bu nedenle, MultiTalentedDriveruygun bir alt sınıftır CarDriver.

Örneğinizde, herhangi IApibiri IConfig. Eğer IHttpApibir alt türü olan IApi, biz inşa etmek gerekir IHttpApiherhangi birini kullanarak IConfigörneği - ama sadece kabul IHttpConfig. Bu bir çelişki.


Tüm sürücüler hem arabaları hem de motosikletleri
süremez

3
@faif: Bu özel soyutlamada sadece yapabilirler, değiller. Gördüğünüz gibi, bir Çünkü Driverherhangi sürebilirim Vehicleve her iki yana Carve Motorcyclegenişletir Vehicle, bütün Driverler hem idare edebilmelidir.
Alex
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.