2012-11-27 12 views
10

Mi piacerebbe riutilizzare più volte una funzionalità in una singola classe. Questa funzionalità si basa su una variabile privata:Come rendere privata una variabile in un tratto?

trait Address { 
    private $address; 

    public function getAddress() { 
     return $this->address; 
    } 

    public function setAddress($address) { 
     $this->address = $address; 
    } 
} 

L'unico modo che ho trovato per use the trait twice, è la seguente:

class User { 
    use Address { 
     getAddress as getHomeAddress; 
     setAddress as setHomeAddress; 

     getAddress as getWorkAddress;    
     setAddress as setWorkAddress; 
    } 
} 

Il problema è, in questo modo, la variabile privata $address è condiviso attraverso i diversi metodi, e il codice non funzionerà come previsto:

$user = new User(); 
$user->setHomeAddress('21 Jump Street'); 
echo $user->getWorkAddress(); // 21 Jump Street 

c'è una soluzione per utilizzare veramente il tratto due volte, pur non condividendo la sua pr ivate variables?

risposta

15

Dichiarazione di una caratteristica con use non creerà un'istanza di quel tratto. I tratti sono fondamentalmente solo codice che viene copiato e incollato nella classe using. Lo as creerà solo un alias per tale metodo, ad es. aggiungerà qualcosa come

public function getHomeAddress() 
{ 
    return $this->getAddress(); 
} 

alla classe utente. Ma sarà ancora solo quella caratteristica. Non ci saranno due diverse proprietà $address, ma solo una.

È possibile rendere privati ​​i metodi e quindi delegare eventuali chiamate pubbliche ad esso tramite __call passando/inserendo il nome del metodo e utilizzando un array per l'indirizzo, ad es.

trait Address { 
    private $address = array(); 

    private function getAddress($type) { 
     return $this->address[$type]; 
    } 

    private function setAddress($type, $address) { 
     $this->address[$type] = $address; 
    } 

    public function __call($method, $args) { 
     switch ($method) { 
      case 'setHomeAddress': 
       return $this->setAddress('home', $args[0]); 
      // more cases … 
     } 
    } 
} 

Ma questa è solo una lattina di vermi.

In altre parole, non si può in modo sano fare ciò che si sta cercando di fare con tratti. O usi due tratti differenti. Oppure usa una buona vecchia aggregazione e aggiungi metodi proxy concreti.

+3

Anche se capisco che i tratti non sono * istanziati *, ero ancora in attesa del loro variabili private non essere visibile alla classe che li utilizzano, quindi, potenzialmente, consentendo di utilizzare più volte in una singola classe, con il metodo aliasing nomi. Sembra che mi sia sbagliato, quindi grazie per la tua risposta! – Benjamin

+0

@Benjamin ogni classe che usa quel tratto avrà la sua istanza della variabile '$ address', ma sarà ovviamente visibile alla classe che lo usa, perché i tratti semplicemente aggiungono un certo comportamento alle classi. –

+0

@Matteo Sì, mi sta diventando un po 'più chiaro nella mia testa ... Questo è diverso dall'eredità multipla, perché con l'ereditarietà la variabile sarebbe visibile solo nella superclasse, dove qui la variabile privata dal carattere è semplicemente "copiata" in la classe attuale. – Benjamin

0

mi ha confermato che è possibile alias la stessa funzione più volte, che era una sorpresa per me. Sebbene ZendStudio appaia solo come "code assist" sull'ultimo alias della funzione.

Essere in grado di alias la stessa funzione più volte si potrebbe prestarsi a qualche comportamento interessante se la funzione di Trait in grado di determinare quale nome è stato chiamato come. Ma non sembra che possiamo determinare la funzione 'alias' all'interno di una funzione di tratto.

Ecco il mio codice di prova:

<?php 
trait TestTrait 
{ 
    public function test() { print __CLASS__ . ', ' . __TRAIT__ . ', ' . __METHOD__ . ', ' . __FUNCTION__ . "\n"; } 
} 
class TestClass 
{ 
    use TestTrait { test as test1; test as test2; } 
} 
$c = new TestClass(); 
$c->test1(); 
$c->test2(); 

uscita:

TestClass, TestTrait, TestTrait::test, test 
TestClass, TestTrait, TestTrait::test, test 

forse sarebbe bello aggiungere un nuovo costante ALIAS per le funzioni di tratto per determinare quali alias sono stati chiamati come.

In realtà ho creato PHP richiesta di funzionalità per questo:

https://bugs.php.net/bug.php?id=63629

0

io possa essere un po 'tardi per il partito, ma il comportamento che si sta tentando di creare non è qualcosa che dovrebbe essere coperto da un tratto, ma per semplice composizione dell'oggetto.

<?php 
class Adddress { 
    private $street; 
    private $number; 
    public function __construct(string $street, ?string $number) {} 
    public function street() : string {} 
    public function number() : string {} 
} 
class User { 
    private $homeAddress; 
    private $workAddress; 
    public function getHomeAddress() : Address {} 
    public function setHomeAddress(Address $homeAddress) : self {} 
    public function getWorkAddress() : Address {} 
    public function setWorkAddress(Address $workAddress) : self {} 
} 
Problemi correlati