2013-01-04 21 views
7

Làm thế nào tôi có thể khởi chạy hàm tạo và hàm hủy được xác định bởi đặc điểm cùng với hàm tạo và hàm hủy của lớp. Ví dụ:Constructor/destructor được xác định bởi đặc tính không được gọi là

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();

Tôi sẽ nhận được một vài dòng văn bản nhưng tôi không nhận được văn bản nào vì hàm tạo của lớp C được gọi rõ ràng thay thế. Có cách nào để đạt được điều này?

Trả lời

5

Các ctor và dtor của C sẽ có ưu tiên hơn ctor đặc điểm và dtor khi lớp gồm:

Một kế thừa thành viên từ một lớp cơ sở sẽ bị thay thế bởi một thành viên chèn vào bởi một Trait. Thứ tự ưu tiên là các thành viên của lớp ghi đè phương thức Trait hiện tại, để bù lại các phương thức kế thừa.

Nguồn: http://php.net/traits

Nói cách khác, loại bỏ các ctor trống và dtor từ C và ctor và dtor của đặc điểm này sẽ được sử dụng. Không có cách nào để làm cho công việc này với cả hai, C và các đặc điểm, ctor và dtor, bởi vì các đặc điểm không hoạt động như thừa kế thông thường.

Nói chung, tôi khuyên bạn không nên cho Traits ctors hoặc dtors của riêng mình bởi vì bạn không thể khởi tạo Traits. Bạn khởi tạo từ một lớp học một Đặc điểm và lớp đó nên được kiểm soát. Thay vào đó, hãy cân nhắc thêm phương thức onCreate() hoặc onDestroy() vào đặc điểm này và gọi chúng từ các phương pháp ma thuật thích hợp trên C. Bạn có thể đạt được điều tương tự bằng cách đánh dấu các đặc điểm __construct trong C, nhưng tôi nghĩ vùng nước này xuống ngữ nghĩa.

+0

Đây không phải là chính xác. Có thể gọi các phương thức của Trait được ghi đè bởi lớp có sử dụng Trait. Nó là đủ để thay đổi tên của các phương pháp trong Trait với cái gì khác. – Aerendir

+0

@Aerendir Nếu đọc của tôi về nguồn C là chính xác, một ctor bí danh hoặc dtor sẽ không chứa các ctor hoặc dtor chức năng cờ nữa. Điều này ngụ ý rằng nó là về mặt kỹ thuật * không khả thi *, bởi vì chúng chỉ là các phương pháp thông thường. Tuy nhiên, rõ ràng là bạn có thể thực hiện chúng * như các phương thức thông thường * bằng cách đánh dấu và điều đó sẽ giải quyết vấn đề của OP một cách hiệu quả.Nhưng điều đó giống như gọi phương thức custom'onCreate() 'hoặc' onDestroy() 'hơn là gọi các ctors hoặc dtors thực tế. – Gordon

2

Bạn phải xác định tên tùy chỉnh cho các phương thức của Trait. Sau đó, bạn có thể gọi những phương thức đó từ lớp của bạn.

Như các phương pháp của lớp ghi đè lên các phương pháp của Trait bạn phải gán một tên khác nhau để các phương pháp của Trait:

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

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

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

bổ sung Aeremdir câu trả lời 's: thừa hưởng nhà xây dựng từ lớp cơ sở và nhiều đặc điểm ...

<?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(); 
?> 

dưới PHP 7.0.5 mã này kết quả trong ...

C1 :: __ construct() thực hiện
T1 :: __ construct() thực hiện
T2 :: __ construct() thực hiện
C2 :: __ construct() thực hiện
0b10100011