Why am I getting Fatal error when calling a parent's constructor?

后端 未结 5 2166
执念已碎
执念已碎 2021-02-11 17:07

I am extending one of the SPL (Standard PHP Library) classes and I am unable to call the parent\'s constructor. Here is the error I am getting:

Fatal erro

相关标签:
5条回答
  • 2021-02-11 17:58

    If you want to call the constructor of the nearest ancestor, you can loop through the ancestors with class_parents and check with method_exists if it has a constructor. If so, call the constructor; if not, continue your search with the next nearest ancestor. Not only do you prevent overriding the parent's constructor, but also that of other ancestors (in case the parent doesn't have a 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';
      }
    
    }
    

    For code reuse, you could also write this code as a function that returns the PHP code to be evaled:

    // 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));
      }
    }
    
    0 讨论(0)
  • 2021-02-11 18:00

    I got the same error. I have solved it by defining an empty constructor in the parent class. That way other classes don't have to define it. I think it's cleaner approach.

    If you still need to call the constructor you can do this.

    if (is_callable('parent::__construct')) {
        parent::__construct();
    }
    
    0 讨论(0)
  • 2021-02-11 18:01

    SplQueue inherits from SplDoublyLinkedList. Neither of these classes defines a constructor of its own. Therefore there's no explicit parent constructor to call, and you get such an error. The documentation is a little misleading on this one (as it is for many SPL classes).

    To solve the error, don't call the parent constructor.


    Now, in most object-oriented languages, you'll expect the default constructor to be called if there isn't an explicit constructor declared in a class. But here's the catch: PHP classes don't have default constructors! A class has a constructor if and only if one is defined.

    In fact, using reflection to analyze the stdClass class, we see even that lacks a constructor:

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

    Attempting to reflect the constructors of SplQueue and SplDoublyLinkedList both yield NULL as well.

    My guess is that when you tell PHP to instantiate a class, it performs all the internal memory allocation it needs for the new object, then looks for a constructor definition and calls it only if a definition of __construct() or <class name>() is found. I went to take a look at the source code, and it seems that PHP just freaks out and dies when it can't find a constructor to call because you told it explicitly to in a subclass (see zend_vm_def.h).

    0 讨论(0)
  • 2021-02-11 18:02

    This error gets thrown, usually, when the parent class being referenced in parent::__construct() actually has no __construct() function.

    0 讨论(0)
  • 2021-02-11 18:06

    You may hack it like this:

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

    but it's helpless.

    just declare constructor explicitly for every class. it's the right behavior.

    0 讨论(0)
提交回复
热议问题