How do I call PHP parent methods from within an inherited method?

前端 未结 4 1237
孤独总比滥情好
孤独总比滥情好 2020-12-18 10:17

In PHP, I\'m trying to reference a method defined in an object\'s parent class, from a method inherited from the object\'s parent class. Here\'s the code:

c         


        
相关标签:
4条回答
  • 2020-12-18 10:29

    I'll start by saying "Thank you" to grrbrr404. He gave me some ideas and got me started in the right direction.

    The solution I finally settled on was the following:

    function inherit_this() {
      $bt = debug_backtrace();
      call_user_func(array($this, get_parent_class($bt[1]['class']) . '::do_something'));
    }
    

    It's not pretty (I particularly hate calling debug_backtrace() for this), but it keeps the object context set to $this, and handles the case where the method is called from a method somewhere in the middle of the object hierarchy.

    For those who found my example confusing and/or wanted to know "Why would you want to do this?" I apologize, and provide the following additional example, which is hopefully more illustrative and closer to the original problem. It is considerably longer, but hopefully shows why I care about keeping $this set properly, and also shows why I can't hard-code any particular class name or use $this->method(). Avoiding infinite loops is always a priority with me. :-)

    class class1_required_type { }
    class class2_required_type { }
    class class3_required_type { }
    class class4_required_type { }
    
    class class1 {
      protected $data = array();
      protected function checkType($name, $value, $requiredType) {
        print "In class1::checkType()\n";
        if (get_class($value) === $requiredType) {
          $backtrace = debug_backtrace();
          call_user_func(array($this, get_parent_class($backtrace[1]['class']) . "::mySet"), $name, $value);
        } else {
          throw new Exception(get_class($this) . "::mySet('" . $name . "') requires an object of type '" . $requiredType . "', but got '" . get_class($value) . "'");
        }
      }
      function mySet($name, $value) {
        print "In class1::mySet()\n";
        if ($name === 'class1_field') {
          $this->checkType($name, $value, 'class1_required_type');
        } else {
          $this->data[$name] = $value;
        }
      }
      function dump() {
        foreach ($this->data as $key => $value) {
          print "$key: " . get_class($value) . "\n";
        }
      }
    }
    
    class class2 extends class1 {
      function mySet($name, $value) {
        print "In class2::mySet()\n";
        if ($name === 'class2_field') {
          $this->checkType($name, $value, 'class2_required_type');
        } else {
          parent::mySet($name, $value);
        }
      }
    }
    
    class class3 extends class2 {
      function mySet($name, $value) {
        print "In class3::mySet()\n";
        if ($name === 'class3_field') {
          $this->checkType($name, $value, 'class3_required_type');
        } else {
          parent::mySet($name, $value);
        }
      }
    }
    
    class class4 extends class3 {
      function mySet($name, $value) {
        print "In class4::mySet()\n";
        if ($name === 'class4_field') {
          $this->checkType($name, $value, 'class4_required_type');
        } else {
          parent::mySet($name, $value);
        }
      }
    }
    
    $obj = new class4;
    $obj->mySet('class3_field', new class3_required_type);
    $obj->dump();
    

    I'm trying to avoid duplication of the "checkType()" function, yet still provide correct behavior even when the hierarchy gets arbitrarily large.

    More elegant solutions are, of course, most welcome.

    0 讨论(0)
  • 2020-12-18 10:31

    To get it work you can modify your base_class like this:

    class base_class {
      function do_something() {
        print "base_class::do_something()\n";
      }
    
     function inherit_this() {
        $this->do_something();
     }
    }
    

    Then your top_clas will call inherit_this() of your base class, but there will be a recursion: do_something() of top_class calls $this->inherit_this(), and in base_class you call again $this->do_something() (in your base class $this will reference to your top_class). Because of that, you will call inherit_this() over and over again.

    You should rename the methods to prevent that.

    Update

    If you want that base_class inherit_this() prints "base_class::do_something" you could modify your base_class like this:

    class base_class {
      function do_something() {
        print "base_class::do_something()\n";
      }
    
      function inherit_this() {
         base_class::do_something();
      }
    

    }

    In this case you make a static call to the base_class method do_something(). The output is top_class::do_something() base_class::do_something()

    Update 2

    Regarding to your comment you can modify your base_class like this:

    class base_class {
      function do_something() {
        print "base_class::do_something()\n";
      }
      function inherit_this() {    
        $par = get_parent_class($this);
        $par::do_something();
      }
    }
    

    You get the parrent class of $this and then call the method. Output will be: top_class::do_something() middle_class::do_something()

    0 讨论(0)
  • 2020-12-18 10:35
    class base_class {
      function do_something() {
        print "base_class::do_something()\n";
      }
      function inherit_this() {
       //parent::do_something();
         $class = get_called_class();
         $class::do_something();
      }
    }
    
    0 讨论(0)
  • 2020-12-18 10:46

    Im not quite sure I understands why you want to do like this. But I guess you cannot do it. I understand that you will be able to make a middle_class2 and be able inherit from that, and then it would be middle_class2 instead of middle_class's dosomething you call?!

    So I guess you'll need to create the

      function inherit_this() {
        parent::do_something();
      }
    

    in the middle_class.

    I thought about a get_class($this)::parent::do_something().. but that didn't work.

    Just to be sure.. You want to call middle_class::do_something() right??

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