2011-01-10 21 views
22

SPL(Standard PHP Library)クラスのいずれかを拡張していて、親のコンストラクタを呼び出すことができません。ここで私は取得していますエラーです:親のコンストラクタを呼び出すときに致命的なエラーが発生するのはなぜですか?

Fatal error: Cannot call constructor

はここSplQueueのドキュメントへのリンクです:http://www.php.net/manual/en/class.splqueue.phpここ

は私のコードは次のとおりです。

$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; 

呼び出してから私を防ぐことができるもの親のコンストラクタ?

+1

ただ、好奇心から、なぜあなたはキュークラスを拡張していますか?あなたは飾り付けをするために何をする必要がありますか? – ircmaxell

答えて

40

SplQueueは、SplDoublyLinkedListから継承されます。これらのクラスのどちらも、独自のコンストラクタを定義しません。したがって、呼び出す明示的な親コンストラクタはなく、このようなエラーが発生します。ドキュメントは、これを少し誤解を招く(多くのSPLクラスの場合と同じように)。

エラーを解決するには、親コンストラクタを呼び出しないでください。


は今、ほとんどのオブジェクト指向言語では、クラスで宣言された明示的なコンストラクタがない場合 デフォルトコンストラクタが呼ばれることを期待しています。しかしここにキャッチがあります: PHPクラスにはデフォルトコンストラクタがありません!クラスには、が定義されている場合にのみ、コンストラクタ があります。実際に

は、stdClassクラスを分析するためにリフレクションを使用して、我々は参照も、そのコンストラクタを欠い:

SplQueueSplDoublyLinkedList両方のコンストラクタを反映しようと
$c = new ReflectionClass('stdClass'); 
var_dump($c->getConstructor()); // NULL 

NULLをもたらします。

私の推測では、あなたがクラスをインスタンス化するためにPHPを伝えるとき、それは新しいオブジェクトに必要なすべての内部メモリ割り当てを行い、その後、コンストラクタの定義を検索し、__construct()または<class name>()の定義のみ場合それを呼び出すことです見つかった。私はソースコードを見に行きました.PHPはちょっと変わってしまい、サブクラスで明示的に言いましたのでコンストラクタを見つけることができませんでした(zend_vm_def.h参照)。

+4

私はPHPが大好きです。私はそれにコンストラクタを追加することを決定したとき、それは親クラスのすべてのサブクラスを通過するように非常に簡単になります... – matt

16

parent::__construct()で参照されているparentクラスが実際には__construct()機能を持たない場合、このエラーはスローされます。

+0

私は同じエラーを取得していますが、私は親クラスでコンストラクタを持って、考えられる理由はありますか? –

+0

親クラスで関数を正しく実装してもよろしいですか? 2つのアンダースコアを持つ '__construct()'。 – Kristian

+0

はい、うまくいきましたが、突然何が起こったのかわかりません。作業をやめて、コンストラクタを呼び出せませんでした。 –

2

あなたはこのようにそれをハック可能性があります

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

が、それは無力です。

すべてのクラスに対して明示的にコンストラクタを宣言します。それは正しい行動です。

2

最も近い祖先のコンストラクタを呼び出す場合は、祖先をclass_parentsでループし、コンストラクタがある場合はmethod_existsでチェックできます。その場合は、コンストラクタを呼び出します。そうでなければ、次の最も近い祖先で検索を続行します。だけでなく、親のコンストラクタをオーバーライド予防するだけでなく、他の先祖のこと(場合には親がコンストラクタを持っていない)でください:

コードの再利用のために
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'; 
    } 

} 

、あなたはまた、機能として、このコードを書くことができていますeval EDになるようにPHPコードを返します。

// 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)); 
    } 
} 
関連する問題