PHP Traiti neden arabirimleri uygulayamıyor?


83

PHP Trait'inin (PHP 5.4) neden arayüzleri uygulayamadığını merak ediyorum.

User1460043'ün answer => ... öğesinden güncelleme, belirli bir arabirimi uygulamak için onu kullanan sınıf gerektiremez

Bunun açık olabileceğini anlıyorum, çünkü insanlar, eğer a'yı Class Akullanan a Trait Tise interface I, Class Adoğrudan interface Idoğruya uygulanmaması gerektiğini düşünebilirler (ve bu doğru değildir çünkü Class Aözellik yöntemlerini yeniden adlandırabilir).

Benim durumumda, benim özelliğim, özelliği kullanan sınıfın uyguladığı arayüzden yöntemleri çağırmaktır.

Özellik aslında bazı arayüz yöntemlerinin bir uygulamasıdır. Bu yüzden, özelliğimi kullanmak isteyen her sınıfın arabirimi uygulaması gerektiğini kodda "tasarlamak" istiyorum. Bu, Trait'in arayüz tarafından tanımlanan sınıf yöntemlerini kullanmasına ve sınıfta mevcut olduklarından emin olmasına izin verir.



13
Konu bu değil, özellikler ve arayüzler arasındaki farkı biliyorum.
Leto

1
Belki teknik bir nedeni vardır ama neden isteyesiniz? Bir özelliği örnekleyemezsiniz, bu nedenle bir arayüz uygulamasına sahip olmak size herhangi bir tip belirleme avantajı sağlamaz. Bunu, dediğiniz gibi, özelliği kullanan sınıfları bir arabirim uygulamaya zorlamak istiyorsanız, o zaman bir (soyut) temel sınıfın daha uygun olup olmayacağını merak ediyorsunuzdur.

Haklısın, soyut sınıfları her yerde kullanabilirim ama kodumu Trait'e güncelliyorum ve bu basit kalıtımla yaşadığım problemleri önlüyor, bu yüzden trait kullanıyorum. Yani belki bu durumda mümkün ama bazılarında değil.
Leto

2
Ya da daha basit terimlerle: neden PHP'de Özellik türleri değil?
nnevala

Yanıtlar:


98

Gerçekten kısa versiyon daha basit çünkü yapamazsınız. Özellikler böyle çalışmaz.

Eğer yazarken use SomeTrait;PHP'de bunu kullanılmakta olduğu sınıfa Süreklik kodu kopyalayıp yapıştırmak için derleyici söylüyorum (etkili) bulunmaktadır.

Çünkü use SomeTrait;sınıf içinde, bu ekleyemezsiniz implements SomeInterfaceo sınıfta dışında olmak zorunda, çünkü sınıfa.

"PHP'de neden Özellik türleri yok?"

Çünkü somutlaştırılamazlar. Özellikler, kodunuz tarafından referans alınabilecek bir nesne veya türün aksine , gerçekten sadece bir dil yapısıdır (derleyiciye özellik kodunu kopyalayıp bu sınıfa yapıştırmasını söyler).

Bu yüzden, özelliğimi kullanmak isteyen her sınıfın arabirimi uygulaması gerektiğini kodda "tasarlamak" istiyorum.

Bu use, özelliğe soyut bir sınıf kullanılarak ve ardından ondan sınıfları genişletilerek zorlanabilir .

interface SomeInterface{
    public function someInterfaceFunction();
}

trait SomeTrait {
    function sayHello(){
        echo "Hello my secret is ".static::$secret;
    }
}

abstract class AbstractClass implements SomeInterface{
    use SomeTrait;
}

class TestClass extends AbstractClass {
    static public  $secret = 12345;

    //function someInterfaceFunction(){
        //Trying to instantiate this class without this function uncommented will throw an error
        //Fatal error: Class TestClass contains 1 abstract method and must therefore be 
        //declared abstract or implement the remaining methods (SomeInterface::doSomething)
    //}
}

$test = new TestClass();

$test->sayHello();

Bununla birlikte - bir Özellik kullanan herhangi bir sınıfın belirli bir yöntemi olduğunu zorlamanız gerekiyorsa, bence ilk etapta soyut sınıflar olmanız gereken özellikleri kullanıyor olabilirsiniz.

Ya da mantığınızın yanlış olduğunu. Arabirimleri uygulayan sınıfların belirli işlevlere sahip olmasını istemeniz gerekir, belirli işlevlere sahipse kendilerini bir arabirim uyguluyor olarak bildirmeleri gerekmez.

Düzenle

Aslında, bir sınıfı yöntemi uygulamaya zorlamak için Traits içinde soyut işlevler tanımlayabilirsiniz. Örneğin

trait LoggerTrait {

    public function debug($message, array $context = array()) {
        $this->log('debug', $message, $context);
    }

    abstract public function log($level, $message, array $context = array());
}

Bununla birlikte, bu yine de arayüzü özellikte uygulamanıza izin vermez ve yine de kötü bir tasarım gibi kokar, çünkü arayüzler bir sınıfın yerine getirmesi gereken bir sözleşmeyi tanımlamada özelliklerden çok daha iyidir.


2
O zaman bunu nasıl düzenlemeyi önerirsiniz, bir İnsan sınıfım var, bu sınıf İşe dayalı olarak alt sınıflara ayrılmıştır, ancak bu işlerin çoğu paylaşılan kodla en iyi şekilde uygulanan özellikleri paylaşır (örneğin hem bir sekreter hem de programcı typeyönteme ). Bunun özellikler olmadan nasıl uygulanabileceğini düşünebiliyor musunuz?
2014

@scragar bunu programmers.stackexchange.com adresinden sormalısınız, ancak kısa versiyon, "İnsan" ı birden çok "İş" ile birleştirerek "ÇalışanHuman" sınıfı oluşturmam.
Danack

1
Bir tane daha. Arayüz bazı farkındalık sözleşmesi tanımlarsa ve bu sözleşme çoğu uygulamada ortaktır. Ancak bu uygulamaların kendi tipi üç vardır. ContainerAwareInterface ile Command gibi bir şey. Ancak Comand'ın kendine özgü kullanım alanları vardır. Bu yüzden, Konteyner Bilincine ihtiyacım olduğu her seferinde kendimi tekrar etmem gerekiyor, ancak Trait'i kullanırsam, belirli bir Arayüz için kendi sözleşmesini tanımlayamam. Belki de çekirdek geliştiriciler Go-Type arayüzlerini (ör. Yapısal Tipleme) düşünmelidir?
lazycommit

3
Bu gerçekten garip, çünkü aslında meslektaşlarım ve ben sadece bir arayüz uygulayan ancak farklı atalardan gelen birkaç sınıfta gerekli olan kodu paylaşmak istediğimizde özellikleri kullanıyoruz. Ayrıca, derleyicinin sınıf içindeki kodu değiştirebildiğini ancak bu sınıf tarafından uygulanan arabirimleri neden değiştiremediğini gösteren makul bir açıklama yoktur. ... bu sadece "eksik" bir özellik ... "çünkü yapamazsınız" bunu en iyi açıklıyor
Summer-Sky

5
PHP çekirdek geliştiricilerinin, özelliklerin tam teşekküllü türler olarak kabul edildiği biraz Scala çalışması gerektiğine inanıyorum ... PHP'nin yazım sistemini kademeli olarak geliştirmek istemesi ancak mevcut iyi çalışan uygulamaları hesaba
katmaması

28

Bir RFC var: Arayüzlere sahip özellikler , dile aşağıdakilerin eklenmesini önerir:

trait SearchItem implements SearchItemInterface
{
    ...
}

Arabirimin gerektirdiği yöntemler, özellik tarafından uygulanabilir veya soyut olarak bildirilebilir, bu durumda özelliği kullanan sınıfın bunu uygulaması beklenir.

Bu özellik şu anda dil tarafından desteklenmemektedir, ancak değerlendirilmektedir (RFC'nin mevcut durumu: Tartışma Altında ).


Sanırım, eğer onaylanırsa, o zaman insanlar normal sınıflardan daha fazla özelliğin özelliklere uygulanmasını isteyecekler. Aralarında hiçbir fark olmayana ve endişeleri ve sorumlulukları düzgün bir şekilde bölmeyen bir tür Frankenstein özelliğine sahip olacağız. En iyi cevabın vurguladığı gibi, özellikler geçmiş kopyalama kolaylığı olarak görülmelidir; sınıfların sınırlarını çok fazla aşmamalı. Uygulama ister doğrudan koddan ister bir özellik kullanımından gelsin, bir sınıfın bir arabirim gerçekleştirmesini istiyoruz; arayüzlerin özelliklere uygulanmasına izin vermek kafa karıştırıcı ve yanıltıcı olabilir
Kamafeather

Özelliklerin harika bir uygulaması, bir arayüzün kolayca yapıştırılabilen varsayılan uygulamasını sağlamaktır. Bir özelliğin bir arayüzü yerine getirdiğinden emin olmak istiyorsanız, derleyicilerin yardımına sahip olmak güzel olurdu
The Mighty Chris

Bu öneri , bir özelliği kullanan bir sınıfın bu özellik arayüzlerini otomatik olarak uygulayacağı anlamına gelmez (özellik yöntemlerini yeniden adlandırabileceğiniz / değiştirebileceğiniz için işe yaramaz). Bunu geçmenin bir şekilde daha agresif gelecekteki RFC'lerden geçeceği şeklindeki kaygan eğim argümanı su tutmamalı
The Mighty Chris

Bence sadece özellikler, arayüzler veya soyut sınıflar olmalıdır. Ve özellikler dildeki tipler olmalıdır.
Dávid Bíró

10

[...] özelliğimi kullanmak isteyen her sınıfın arayüzü uygulamak zorunda olduğu kodda "tasarlamak". Bu, Trait'in arayüz tarafından tanımlanan sınıf yöntemlerini kullanmasına ve sınıfta mevcut olduklarından emin olmasına izin verir.

Bu kulağa çok mantıklı geliyor ve tasarımınızda yanlış bir şey olması gerektiğini söylemem. Bu fikir akılda tutularak özellikler önerilmiştir, buradaki ikinci noktaya bakın:

  • Bir özellik , davranışı uygulayan bir dizi yöntem sağlar .
  • Bir özellik , sağlanan davranış için parametre görevi gören bir dizi yöntem gerektirir .
  • [...]

Schärli ve diğerleri, Özellikler: Composable Units of Behavior, ECOOP'2003, LNCS 2743, pp. 248–274, Springer Verlag, 2003, Sayfa 2

Bu nedenle, bir özelliği "uygulamak" yerine bir arayüz gerektirmesini istediğinizi söylemek belki daha uygun olacaktır .

PHP'de bu "özelliğin (tüketici sınıflarının uygulanması için) bir arayüz gerektirmesi" özelliğine sahip olmanın neden imkansız olması gerektiğine dair bir neden göremiyorum, ancak şu anda eksik görünüyor.

Onun içinde @Danack notları gibi cevap yapmanız özellikte soyut işlevleri kullanabilirsiniz onlara özelliği kullanmak sınıflardan "iste". Maalesef bunu özel işlevlerle yapamazsınız .


1

@Danack'ın cevabına katılıyorum, ancak biraz tamamlayacağım.

Gerçekten kısa versiyon daha basit çünkü yapamazsınız. Özellikler böyle çalışmaz.

İstediğiniz şeyin gerekli olduğu ve bir dil başarısızlığından çok bir tasarım problemi olarak daha belirgin olduğu sadece birkaç durum düşünebiliyorum. Bunun gibi bir arayüz olduğunu hayal edin:

interface Weaponize
{
    public function hasAmmunition();
    public function pullTrigger();
    public function fire();
    public function recharge();
}

Bir özellik tanımlanan fonksiyonların uygular biri olduğunu oluşturuldu arayüzünde ama süreç içinde de tanımlanan diğer işlevleri kullanan bir arayüz özelliğini kullanır sınıf uygulamaması halinde bu hata eğilimli, arayüz olanklari başarısız tetiklemek

trait Triggerable
{
    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}

class Warrior
{
    use Triggerable;
}

Basit bir çözüm, özelliği kullanan sınıfı bu işlevleri de uygulamaya zorlamaktır :

trait Triggerable
{
    public abstract function hasAmmunition();
    public abstract function fire();

    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}

Bu nedenle özellik tamamen arayüze bağlı değildir , ancak işlevlerinden birini uygulama önerisi, özelliği kullanırken sınıf soyut yöntemlerin uygulanmasını talep edecektir.

Son tasarım

interface Weaponize
{
    public function hasAmmunition();
    public function pullTrigger();
    public function fire();
    public function recharge();
}

trait Triggerable
{
    public abstract function hasAmmunition();
    public abstract function fire();

    public function pullTrigger()
    {
        if ($this->hasAmmunition()) {
            $this->fire();
        }
    }
}


class Warrior implements Weaponize
{
    use Triggerable;

    public function hasAmmunition()
    {
        // TODO: Implement hasAmmunition() method.
    }

    public function fire()
    {
        // TODO: Implement fire() method.
    }

    public function recharge()
    {
        // TODO: Implement recharge() method.
    }
}

Lütfen ingilizcemi affedin

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.