2011-01-10 19 views
22

मैं एसपीएल (मानक PHP लाइब्रेरी) कक्षाओं में से एक को विस्तारित कर रहा हूं और मैं अभिभावक के निर्माता को कॉल करने में असमर्थ हूं।माता-पिता के कन्स्ट्रक्टर को कॉल करते समय मुझे घातक त्रुटि क्यों मिल रही है?

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

SplQueueSplDoublyLinkedList से विरासत प्राप्त करता है। इन वर्गों में से कोई भी अपने स्वयं के निर्माता को परिभाषित नहीं करता है। इसलिए कॉल करने के लिए कोई स्पष्ट अभिभावक कन्स्ट्रक्टर नहीं है, और आपको ऐसी त्रुटि मिलती है। दस्तावेज इस पर थोड़ा भ्रामक है (क्योंकि यह कई एसपीएल वर्गों के लिए है)।

त्रुटि को हल करने के लिए, मूल निर्माता को कॉल न करें।


अब, सबसे वस्तु उन्मुख भाषाओं में, आप अगर वहाँ एक स्पष्ट निर्माता एक वर्ग में घोषित नहीं किया है डिफ़ॉल्ट निर्माता कहा जा करने की उम्मीद की जाती है। लेकिन यहां पकड़ है: PHP कक्षाओं में डिफ़ॉल्ट निर्माता नहीं हैं! एक वर्ग में एक कन्स्ट्रक्टर है और केवल अगर किसी को परिभाषित किया गया है।

वास्तव में, प्रतिबिंब का उपयोग stdClass वर्ग का विश्लेषण करने के लिए, हम भी देख सकते हैं कि एक निर्माता का अभाव:

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

SplQueue और SplDoublyLinkedList के निर्माताओं को प्रतिबिंबित करने के प्रयास कर रहा है दोनों के रूप में अच्छी उपज NULL

मेरा अनुमान है कि जब आप एक वर्ग का दृष्टांत को पीएचपी बता, यह सब आंतरिक स्मृति आवंटन यह नई वस्तु के लिए की जरूरत है करता है, तो एक निर्माता परिभाषा के लिए लग रहा है और यह कहता है केवल तभी एक __construct() या <class name>() की परिभाषा है पाया जाता है। मैं सोर्स कोड पर एक नज़र डालने के लिए गया, और ऐसा लगता है कि PHP केवल कॉलक करता है और मर जाता है जब इसे कॉल करने के लिए कोई कन्स्ट्रक्टर नहीं मिल रहा है क्योंकि आपने इसे उप-वर्ग में स्पष्ट रूप से बताया है (zend_vm_def.h देखें)।

+4

मुझे PHP पसंद है। जब मैं इसे कन्स्ट्रक्टर जोड़ने का फैसला करता हूं तो माता-पिता वर्ग के सभी उप वर्गों के माध्यम से जाना बहुत आसान होगा ... – matt

16

यह त्रुटि parentparent::__construct() में संदर्भित होने वाली कक्षा में वास्तव में __construct() फ़ंक्शन में संदर्भित होने पर यह त्रुटि फेंक दी जाती है।

+0

मुझे एक ही त्रुटि मिल रही है, लेकिन मेरे पास मेरे मूल वर्ग में निर्माता है, क्या आप मुझे बता सकते हैं कि क्या कर सकता है संभावित कारण हो सकता है? –

+0

क्या आप वाकई पैरेंट क्लास में फ़ंक्शन को सही तरीके से कार्यान्वित कर चुके हैं? 'अंडरस्कोर – Kristian

+0

के साथ __construct()' हाँ, और यह ठीक काम कर रहा था, लेकिन यह नहीं पता कि अचानक क्या हुआ, यह काम करना बंद कर दिया और घातक त्रुटि को फेंकना 'कन्स्ट्रक्टर को कॉल नहीं कर सकता'। –

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 एड होने के लिए 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)); 
    } 
} 
संबंधित मुद्दे