2013-01-04 14 views
7

Come posso avviare il costruttore e il distruttore definiti da tratto insieme al costruttore e al distruttore della classe. Ad esempio,Il costruttore/distruttore definito da tratto non viene chiamato

trait Audit 
{ 
    public function __construct() 
    { 
     parent::__construct(); // Doesn't work... 

     $this->_name = __CLASS__; 

     $this->AuditAction('Started'); 
    } 

    public function __destruct() 
    { 
     parent::__destruct(); // Doesn't work... 

     $this->AuditAction('Ended'); 

     echo $this->_log;   
    } 

    public function AuditAction($n) 
    { 
     $this->_log .= $this->GetCurrentTimeStamp() . ' ' . $this->_name . ": $n" . PHP_EOL; 
    } 

    private function GetCurrentTimeStamp() 
    { 
     return (new DateTime())->format('[Y-m-d H:i:s]'); 
    } 

    private $_name, $_log = ''; 
} 

class C 
{ 
    use Audit; 

    public function __construct() 
    { 

    } 

    public function __destruct() 
    { 

    } 
} 

$c = new C();

dovrei ottenere paio di righe di testo ma ottengo nessuno dal costruttore della classe di C è esplicitamente chiamato invece. C'è un modo per ottenere questo?

risposta

5

ctor e dtor di C avrà la precedenza sul ctor tratto e dtor quando la classe è composta:

Un membro ereditato da una classe di base viene sovrascritto da un elemento inserito da un tratto. L'ordine di precedenza è che i membri della classe corrente eseguano l'override dei metodi Trait, che in cambio annullano i metodi ereditati.

Fonte: http://php.net/traits

In altre parole, rimuovere il ctor vuoto e dtor da C e verrà utilizzato ctor e dtor del tratto. Non c'è modo di farlo funzionare con entrambi, C e i tratti, il direttore e il direttore, perché i tratti non funzionano come un'eredità regolare.

In generale, consiglierei di non dare a Tratti i propri medici o medici perché non è possibile istanziare i tratti. Si istanzia da una classe con un tratto e quella classe dovrebbe avere il controllo. Potresti aggiungere un metodo onCreate() o onDestroy() al carattere e chiamarli dai metodi magici appropriati su C. Puoi ottenere lo stesso facendo l'aliasing dei tratti __Construct in C, ma penso che questo scoraggi la semantica.

+0

Questo non è corretto. È possibile chiamare metodi del Tratto che vengono sovrascritti dalla classe che utilizza il Tratto. È sufficiente cambiare il nome dei metodi nel Tratto con qualcos'altro. – Aerendir

+0

@Airendir Se la mia lettura della sorgente C è corretta, un ctor o un datore di alias non conterrà più i flag di funzione ctor o dtor. Ciò implica che tecnicamente * non è possibile *, perché sono solo metodi regolari allora. Tuttavia, hai ovviamente ragione che puoi eseguirli * come metodi regolari * tramite aliasing e che risolveranno efficacemente il problema dell'OP.Ma è più come chiamare un metodo personalizzato 'onCreate()' o 'onDestroy()' piuttosto che chiamare veri e propri operatori. – Gordon

2

È necessario definire un nome personalizzato per i metodi di Trait. Quindi puoi chiamare quel metodo dalla tua classe.

Mentre i metodi della classe sovrascrivono i metodi della Trait è necessario assegnare un nome diverso per i metodi della Trait:

class C 
{ 
    use Audit { 
     Audit::__construct as auditConstruct; 
     Audit::__destruct as auditDestruct; 
    } 

    public function __construct() 
    { 
     $this->auditConstruct(); 
    } 

    public function __destruct() 
    { 
     $this->auditDestruct(); 
    } 
} 
2

Oltre a Aeremdir 's risposta: ereditato costruttori dalla classe base e molteplici tratti ...

<?php 
    trait T1 { 
    public function __construct() { 
     $this->someval |= 0b0001; 
     echo "T1::__construct() done\n"; 
    } 
    } 

    trait T2 { 
    public function __construct() { 
     $this->someval |= 0b0010; 
     echo "T2::__construct() done\n"; 
    } 
    } 

    class C1 { 
    protected $someval; 

    public function __construct() { 
     $this->someval = 0b10000000; 
     echo "C1::__construct() done\n"; 
    } 
    } 

    class C2 extends C1 { 
    use T1, T2 { 
     T1::__construct as private T1__construct; 
     T2::__construct as private T2__construct; 
    } 

    public function __construct() { 
     parent::__construct(); 
     $this->T1__construct(); 
     $this->T2__construct(); 

     $this->someval |= 0b00100000; 
     echo "C2::__construct() done\n"; 
    } 

    public function someval() { 
     $str = base_convert($this->someval, 10, 2); 
     $len = strlen($str); 
     if($len < 8) 
      $str = str_repeat('0', 8 - $len) . $str; 

     return '0b' . $str; 
    } 
    } 

    $v1 = new C2(); 
    echo $v1->someval(); 
?> 

sotto PHP 7.0.5 questo codice si traduce in ...

C1 :: __ construct() fatto
T1 :: __ construct() fatto
T2 :: __ construct() fatto
C2 :: __ construct() fatto
0b10100011

Problemi correlati