Özellik fonksiyonunu geçersiz kılma ve geçersiz kılma fonksiyonundan çağırma nasıl yapılır?


370

Senaryo:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A;

    function calc($v) {
        $v++;
        return A::calc($v);
    }
}

print (new MyClass())->calc(2); // should print 4

Bu kod çalışmıyor ve devralınmış gibi bir özellik işlevini çağırmak için bir yol bulamıyorum. Ben aradım self::calc($v), static::calc($v), parent::calc($v), A::calc($v)ve şu:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as traitcalc;
    }

    function calc($v) {
        $v++;
        return traitcalc($v);
    }
}

Hiç birşey çalışmıyor.

Çalıştırmak için bir yolu var mı veya tamamen bundan daha karmaşık olan özellik işlevini geçersiz kılmalıyım :)

Yanıtlar:


641

Sonuncunuz neredeyse oradaydı:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    use A {
        calc as protected traitcalc;
    }

    function calc($v) {
        $v++;
        return $this->traitcalc($v);
    }
}

Özellik bir sınıf değildir. Üyelerine doğrudan erişemezsiniz. Temelde sadece otomatik kopyala ve yapıştır ...


20
sadece açıklığa kavuşturmak için - sınıfınız aynı yöntemi tanımladığında, özellik otomatik olarak geçersiz kılınır. Özellik @ircmaxell boş olduğunda belirtildiği gibi yöntemi doldurur.
Yehosef

2
@PhillipWhelan, "beklendiği gibi çalışmaz" durumuyla ilgili daha fazla bilgi ekleyebilirseniz iyi olur. Böyle yazılması, ne tür bir yanlış davranışın beklendiğini anlamada çok yardımcı olmaz ve bunun sizin geçici bir hata olmadığından emin olmamızı sağlamaz. Belki de bahsettiğiniz sorun hakkında bazı SO soruları var mı? (Sonunda) Teşekkürler.
Kamafeather

1
Sorun, özellikteki diğer tüm yöntemlerin artık dahil edilmemesidir.
malhal

2
Sadece referans için: Eğer özellik fonksiyonunuz statik olsaydı, fonksiyona erişebilirsinizA::calc(1)
velop

4
Phillip'in dediği gibi (sanırım), normaldeki aynı özelliğin diğer tüm yöntemlerini dahil ederken bunu bir özelliğin yöntemi için nasıl yapardınız? Tercihen her yönteme açıkça atıfta bulunulmadan.
Gannet

14

Sınıf yöntemi doğrudan uygularsa, özellik sürümünü kullanmayacaktır. Belki de düşündüğünüz şey:

trait A {
    function calc($v) {
        return $v+1;
    }
}

class MyClass {
    function calc($v) {
        return $v+2;
    }
}

class MyChildClass extends MyClass{
}

class MyTraitChildClass extends MyClass{
    use A;
}

print (new MyChildClass())->calc(2); // will print 4

print (new MyTraitChildClass())->calc(2); // will print 3

Alt sınıflar yöntemi doğrudan uygulamadığından, ana sınıfın başka türünü kullanırlarsa, önce özelliğin özelliğini kullanırlar.

İsterseniz, özellik üst sınıftaki yöntemi kullanabilir (yöntemin orada olacağını bildiğinizi varsayarak) örn.

trait A {
    function calc($v) {
        return parent::calc($v*3);
    }
}
// .... other code from above
print (new MyTraitChildClass())->calc(2); // will print 8 (2*3 + 2)

Ayrıca, geçersiz kılma yöntemleri de sağlayabilirsiniz, ancak yine de aşağıdaki gibi trait yöntemine erişebilirsiniz:

trait A {
    function trait_calc($v) {
        return $v*3;
    }
}

class MyClass {
    function calc($v) {
        return $v+2;
    }
}


class MyTraitChildClass extends MyClass{
    use A {
      A::trait_calc as calc;
    }
}


class MySecondTraitChildClass extends MyClass{
    use A {
      A::trait_calc as calc;
    }

    public function calc($v) {
      return $this->trait_calc($v)+.5;
    }
}


print (new MyTraitChildClass())->calc(2); // will print 6
echo "\n";
print (new MySecondTraitChildClass())->calc(2); // will print 6.5

Çalıştığını http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5 adresinde görebilirsiniz.


8

İlgileniyorsa alternatif bir yaklaşım - normal OOO yolunu kullanmak için ekstra bir ara sınıfla. Bu, parent :: methodname ile kullanımı basitleştirir

trait A {
    function calc($v) {
        return $v+1;
    }
}

// an intermediate class that just uses the trait
class IntClass {
    use A;
}

// an extended class from IntClass
class MyClass extends IntClass {
    function calc($v) {
        $v++;
        return parent::calc($v);
    }
}

6
Bu yaklaşım, traits'yi kullanarak sahip olduğunuz tüm avantajları tıraş edecektir . Birden çok sınıftaki birden çok özelliği birleştirmek gibi (örneğin bir sınıftaki A, B özelliği, başka bir sınıftaki B, C, D özelliği, başka bir sınıftaki A, C özelliği vb.)
Ionuț Staicu

3
Hayır, bu yaklaşımı kullanarak hala bir özelliğe sahip olmanın avantajlarına sahipsiniz. Bu özelliği IntClass'ta kullanabilirsiniz, ancak isterseniz başka birçok sınıfta da kullanabilirsiniz. Yalnızca IntClass içinde kullanılmışsa, özellik işe yaramaz. Bu durumda, calc () yöntemini doğrudan bu sınıfa yerleştirmek daha iyi olur.
marcini

Bu benim için kesinlikle işe yaramaz. ScreenablePerson::save()var, özelliği Candidatekullanır Validatingve genişletir ScreenablePersonve her üç sınıf da vardır save().
Theodore R. Smith

1

Başka bir özellik kullanma:

trait ATrait {
    function calc($v) {
        return $v+1;
    }
}

class A {
    use ATrait;
}

trait BTrait {
    function calc($v) {
        $v++;
        return parent::calc($v);
    }
}

class B extends A {
    use BTrait;
}

print (new B())->calc(2); // should print 4
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.