2012-09-18 23 views
43

Trong PHP 5, tôi có thể để quá tải constructors (và bất kỳ phương pháp khác). Nhưng nếu tôi nhận được một số mã như thế này:Làm thế nào để quá tải lớp xây dựng trong những đặc điểm trong PHP> = 5.4

class Base { 

    public function __construct($a, $b) { 
     echo $a+$b; 
    } 


    public function sayHello() { 
     echo 'Hello '; 
    } 
} 


trait SayWorld { 

    public function __construct($a, $b, $c = 0) { 
     echo (int)$c * ($a+$b); 
    } 

    public function sayHello($a = null) { 
     parent::sayHello(); 
     echo 'World!'.$a; 
    } 
} 

class MyHelloWorld extends Base { 
    use SayWorld; 
} 

$o = new MyHelloWorld(2, 3); 
$o->sayHello(1); 

Tôi có một lỗi:

Fatal error: MyHelloWorld has colliding constructor definitions coming from traits

Làm thế nào tôi có thể sửa chữa nó? Bạn có thể kiểm tra mã của tôi here.

+1

Chỉ là cảnh báo.Bí danh tra cứu sẽ khiến PHP bị lỗi là 5.4.7, đặc biệt với các trình nạp tự động. Một sửa chữa đã được thêm vào repo, vì vậy hy vọng nó sẽ hiển thị trong phiên bản tiếp theo. – Matthew

Trả lời

81

Tôi nghĩ bây giờ cách duy nhất để làm những gì bạn muốn là:

class MyHelloWorld extends Base { 

    use SayWorld { 
     SayWorld::__construct as private __swConstruct; 
    } 

    public function __construct($a, $b, $c = 0) 
    { 
     $this->__swConstruct($a, $b, $c); 
    } 
} 

Chỉnh sửa 2:

Lời khuyên của tôi, dựa trên hơn một năm đối phó với đặc điểm s trong PHP, là: tránh viết các hàm tạo trong các đặc điểm ở tất cả, hoặc nếu bạn phải - ít nhất là làm cho chúng không có tham số. Có được họ trong các đặc điểm đi ngược lại ý tưởng của các nhà thầu nói chung, đó là: các nhà thầu phải cụ thể cho một lớp mà họ thuộc về. Các ngôn ngữ cấp cao khác, phát triển thậm chí không hỗ trợ kế thừa hàm tạo dựng ngầm. Điều này là do các nhà xây dựng có mối quan hệ mạnh mẽ hơn nhiều so với lớp rồi các phương pháp khác. Trong thực tế, họ có mối quan hệ rất mạnh mẽ, mà ngay cả các LSP không áp dụng cho họ. Những đặc điểm trong ngôn ngữ Scala (một người rất thành công và SOLID là người kế thừa thân thiện của Java), can't have a constructor with parameters.

Sửa 1:

Có một bug trong PHP 5.4.11, mà thực sự được phép bí danh một phương pháp lớp cha. Nhưng điều này được coi là một không-không có bởi các nhà phát triển PHP, vì vậy chúng tôi vẫn còn bị mắc kẹt với giải pháp rườm rà mà tôi đã trình bày ở trên. Nhưng lỗi đó đưa ra một cuộc thảo luận về những gì có thể được thực hiện với điều này, và tôi hy vọng nó sẽ được nhắm mục tiêu trong các phiên bản tương lai.

Trong khi đó, tôi gặp phải vấn đề tương tự lặp đi lặp lại. Kích thích của tôi tăng lên theo cấp số nhân với số lượng tham số và dòng của docblock đã được lặp lại rất nhiều lần để sử dụng đặc điểm đó. Vì vậy, tôi đã đưa ra mô hình sau để dính vào các quy tắc DRY nhiều như tôi có thể:

Thay vì lặp lại toàn bộ các thông số như thế này:

trait SayWorld { 

    /** 
    * This is a valid docblock. 
    * 
    * @param int $a Doc comment. 
    * @param int $b Doc comment. 
    */ 
    public function __construct($a, $b) { 
     echo (int)$c * ($a+$b); 
    } 
} 

class MyHelloWorld extends Base { 

    use SayWorld { 
     SayWorld::__construct as private __swConstruct; 
    } 

    /** 
    * Repeated and unnecessary docblock. 
    * 
    * @param int $a Doc comment. 
    * @param int $b Doc comment. 
    * @param int $c Doc comment. 
    */ 
    public function __construct($a, $b, $c = 0) 
    { 
     $this->__swConstruct($a, $b); 
    } 
} 

tôi viết một lớp giống như một tuple (khái niệm quen thuộc với C#Python người dùng), và sử dụng nó thay vì một danh sách vô tận của các thông số:

class SayWorldConstructTuple 
{ 
    public $a; 

    public $b; 

    public function __construct($a, $b) 
    { 
     $this->a = $a; 
     $this->b = $b; 
    } 
} 

class MyHelloWorld extends Base { 

    use SayWorld { 
     SayWorld::__construct as private __swConstruct; 
    } 

    /** 
    * New and valid docblock. 
    * 
    * @param SayWorldConstructTuple $Tuple 
    * @param int $c Additional parameter. 
    */ 
    public function __construct(SayWorldConstructTuple $Tuple, $c = 0) 
    { 
     $this->__swConstruct($Tuple->a, $Tuple->b); 
     $this->c = $c; 
    } 
} 

Lưu ý: mô hình này là tất nhiên hữu ích hơn với a la số lượng lớn hơn các tham số hàm tạo của tuple và các lớp khác sử dụng bộ tuple.

Nó có thể được tự động thêm với việc sử dụng tính chất động của PHP.

+11

+1 cho' tránh viết các hàm tạo trong các đặc điểm ở tất cả' với lời giải thích – Dennis

+0

Thiên tài! Nó hoạt động :) – Robert

5

Hãy thử:

use SayWorld { 
    Base::__construct insteadof SayWorld; 
} 

Ref: PHP Docs

+0

* gật đầu *, đẹp +1 – wesside

+0

Tôi đã thử nó. Đã ** bạn ** đã cố chạy mã của riêng bạn chưa? Nó trả về MyHelloWorld có các định nghĩa của hàm dựng xây dựng đến từ các đặc điểm lỗi nghiêm trọng. –

+0

Xin lỗi, sai lầm của tôi là tự tin tôi đã có nó đúng cách xung quanh;) ... Cố định! – Martin

Các vấn đề liên quan