2011-01-10 75 views
22

Tôi đang mở rộng một trong các lớp SPL (Thư viện PHP chuẩn) và tôi không thể gọi hàm tạo của cha mẹ. Dưới đây là lỗi Tôi nhận:Tại sao tôi gặp lỗi nghiêm trọng khi gọi hàm tạo của cha mẹ?

Fatal error: Cannot call constructor

Dưới đây là một liên kết đến 's SplQueue tài liệu: http://www.php.net/manual/en/class.splqueue.php

đây là mã của tôi:

$queue = new Queue(); 

class Queue extends SplQueue { 

    public function __construct() { 
     echo 'before'; 
     parent::__construct(); 
     echo 'I have made it after the parent constructor call'; 
    } 

} 

exit; 

gì có thể ngăn cản tôi từ cách gọi constructor của cha mẹ?

+1

Chỉ vì tò mò, tại sao bạn mở rộng lớp xếp hàng? Những gì bạn cần để làm trang trí đó sẽ không? – ircmaxell

Trả lời

40

SplQueue được kế thừa từ SplDoublyLinkedList. Cả hai lớp này không định nghĩa một hàm tạo riêng của nó. Do đó không có hàm khởi tạo cha mẹ rõ ràng nào để gọi và bạn nhận được một lỗi như vậy. Tài liệu này có chút ít gây hiểu nhầm về vấn đề này (vì nó dành cho nhiều lớp SPL).

Để giải quyết lỗi, không gọi hàm khởi tạo gốc.


Bây giờ, trong hầu hết các ngôn ngữ hướng đối tượng, bạn sẽ mong đợi mặc định constructor được gọi là nếu không có một nhà xây dựng rõ ràng tuyên bố trong một lớp học. Nhưng đây là bắt: Các lớp PHP không có các hàm tạo mặc định! Một lớp có một hàm tạo nếu và chỉ khi một được xác định.

Trong thực tế, sử dụng phản chiếu để phân tích các lớp stdClass, chúng ta thấy thậm chí thiếu một constructor:

$c = new ReflectionClass('stdClass'); 
var_dump($c->getConstructor()); // NULL 

Cố gắng để phản ánh các nhà thầu của SplQueueSplDoublyLinkedList cả mang lại NULL là tốt.

tôi đoán là khi bạn nói với PHP để thuyết minh một lớp, nó thực hiện tất cả các phân bổ bộ nhớ cần thiết cho các đối tượng mới, sau đó tìm kiếm một định nghĩa constructor và gọi đó là chỉ khi một định nghĩa của __construct() hoặc <class name>() được tìm thấy. Tôi đã đi để xem xét mã nguồn, và có vẻ như PHP chỉ freaks ra và chết khi nó không thể tìm thấy một nhà xây dựng để gọi bởi vì bạn nói với nó một cách rõ ràng để trong một phân lớp (xem zend_vm_def.h).

+4

Tôi yêu PHP. Nó sẽ rất dễ dàng để đi qua tất cả các lớp con của lớp cha mẹ khi tôi quyết định thêm hàm tạo vào nó ... – matt

16

Lỗi này bị ném, thường là khi lớp parent được tham chiếu trong parent::__construct() thực sự không có chức năng __construct().

+0

Tôi nhận được cùng một lỗi, nhưng tôi có hàm tạo trong lớp cha, bạn có thể cho tôi biết những gì có thể là lý do có thể? –

+0

Bạn có chắc là bạn đã triển khai đúng chức năng trong lớp cha? '__construct()' với 2 dấu gạch dưới – Kristian

+0

Có, và nó hoạt động tốt, nhưng không biết điều gì đã xảy ra đột ngột, Nó ngừng hoạt động và tiếp tục ném lỗi chết người 'Không thể gọi hàm tạo'. –

2

Bạn có thể hack nó như thế này:

if (in_array('__construct', get_class_methods(get_parent_class($this)))) { 
    parent::__construct(); 
} 

nhưng nó không nơi nương tựa.

chỉ khai báo hàm tạo một cách rõ ràng cho mọi lớp. đó là hành vi đúng đắn.

2

Nếu bạn muốn gọi hàm tạo của tổ tiên gần nhất, bạn có thể lặp qua tổ tiên với class_parents và kiểm tra với method_exists nếu nó có hàm tạo. Nếu có, hãy gọi hàm tạo; nếu không, hãy tiếp tục tìm kiếm của bạn với tổ tiên gần nhất tiếp theo.Không chỉ làm bạn ngăn chặn trọng constructor của cha mẹ, mà còn là của tổ tiên khác (trong trường hợp phụ huynh không có một constructor):

class Queue extends SplQueue { 

    public function __construct() { 
    echo 'before'; 

    // loops through all ancestors 
    foreach(class_parents($this) as $ancestor) { 

     // check if constructor has been defined 
     if(method_exists($ancestor, "__construct")) { 

     // execute constructor of ancestor 
     eval($ancestor."::__construct();"); 

     // exit loop if constructor is defined 
     // this avoids calling the same constructor twice 
     // e.g. when the parent's constructor already 
     // calls the grandparent's constructor 
     break; 
     } 
    } 
    echo 'I have made it after the parent constructor call'; 
    } 

} 

Đối với tái sử dụng mã, bạn cũng có thể viết mã này như một chức năng mà trả về mã PHP là eval ed:

// define function to be used within various classes 
function get_parent_construct($obj) { 

    // loop through all ancestors 
    foreach(class_parents($obj) as $ancestor) { 

    // check if constructor has been defined 
    if(method_exists($ancestor, "__construct")) { 

     // return PHP code (call of ancestor's constructor) 
     // this will automatically break the loop 
     return $ancestor."::__construct();"; 
    } 
    } 
} 

class Queue extends SplQueue { 

    public function __construct() { 
    echo 'before'; 

    // execute the string returned by the function 
    // eval doesn't throw errors if nothing is returned 
    eval(get_parent_construct($this)); 
    echo 'I have made it after the parent constructor call'; 
    } 
} 

// another class to show code reuse 
class AnotherChildClass extends AnotherParentClass { 

    public function __construct() { 
    eval(get_parent_construct($this)); 
    } 
} 
Các vấn đề liên quan