2012-08-13 1 views
249

Scenario:Come sovrascrivere la funzione tratti e chiamarla dalla funzione ignorata?

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 

Questo codice non funziona, e non riesco a trovare un modo per chiamare una funzione caratteristica come è stato ereditato. Ho provato a chiamare self::calc($v), static::calc($v), parent::calc($v), A::calc($v) e la seguente:

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

class MyClass { 
    use A { 
     calc as traitcalc; 
    } 

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

Niente funziona.

C'è un modo per farlo funzionare o devo ignorare completamente la funzione tratto che è molto più complessa di così :)

risposta

431

tuo ultimo era quasi arrivato:

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

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

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

Il tratto è non una classe. Non è possibile accedere ai suoi membri direttamente. Fondamentalmente è solo copia e incolla automatica ...

+2

Perfetto! Grazie! Ovviamente il mio cervello non si è sciolto. :) – Shu

+8

solo per chiarire: una volta che la classe definisce lo stesso metodo, sovrascrive automaticamente le caratteristiche del tratto. Il tratto riempie il metodo come @ircmaxell menziona quando è vuoto. – Yehosef

+0

Per ragioni ancora sconosciute questo ha completamente rovinato un tratto con cui ho applicato questo. Gli altri metodi in cui il tratto sta entrando potrebbero non funzionare come previsto quando lo fai. –

7

Se la classe implementa direttamente il metodo, non utilizzerà la versione dei tratti. Forse quello che stai pensando è:

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 

Poiché le classi figlie non implementano direttamente il metodo, che per prima cosa utilizzare quella del tratto se altrimenti c'è uso che della classe padre.

Se lo si desidera, il tratto può utilizzare il metodo nella classe padre (presumendo che il metodo sia presente) ad es.

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) 

È inoltre possibile fornire nuovi modi per eseguire l'override, ma ancora accedere al metodo trait come segue:

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 

si può vedere lavorare a http://sandbox.onlinephpfunctions.com/code/e53f6e8f9834aea5e038aec4766ac7e1c19cc2b5

4

Un approccio alternativo se interessati - con una classe intermedia extra per usare il normale modo OOO. Ciò semplifica l'utilizzo con parent :: methodname

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); 
    } 
} 
+5

Questo approccio eliminerà qualsiasi vantaggio utilizzando i 'trait's. Come combinare più tratti in più classi (ad esempio tratto A, B in una classe, tratto B, C, D in un'altra classe, tratto A, C in un'altra classe e così via) –

+3

No, usando questo approccio hai ancora i vantaggi di avere un tratto. Puoi usare questo tratto in IntClass, ma puoi anche usarlo in molte altre classi, se lo desideri. Tratto sarà inutile, se fosse usato solo in IntClass. In tal caso, sarebbe meglio posizionare il metodo calc() direttamente in quella classe. – marcini

0

Utilizzando un altro tratto:

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