How do I call PHP parent methods from within an in

2020-02-11 06:23发布

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:

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

$obj = new top_class;
$obj->do_something();

The problem is that parent::do_something() in inherit_this() tries to find the parent class of base_class, not the parent of the object's actual class, and the example above throws an error. Is there something I can write instead of parent::do_something() that would call middle_class::do_something(), and that would still work even in classes that extend (say) top_class?

4条回答
够拽才男人
2楼-- · 2020-02-11 07:01

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.

查看更多
再贱就再见
3楼-- · 2020-02-11 07:04
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();
  }
}
查看更多
Luminary・发光体
4楼-- · 2020-02-11 07:12

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??

查看更多
萌系小妹纸
5楼-- · 2020-02-11 07:16

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()

查看更多
登录 后发表回答