【问题标题】:How do I call PHP parent methods from within an inherited method?如何从继承的方法中调用 PHP 父方法?
【发布时间】:2012-01-06 02:41:38
【问题描述】:

在 PHP 中,我试图从从对象的父类继承的方法中引用在对象的父类中定义的方法。代码如下:

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

问题是inherit_this()中的parent::do_something()试图找到base_class的父类,而不是对象实际类的父类,上面的例子抛出了错误。有没有我可以写的东西来代替 parent::do_something() 来调用 middle_class::do_something(),并且即使在扩展(比如)top_class 的类中仍然可以工作?

【问题讨论】:

  • 能不能不用php5,然后为base_class创建一个私有的方法?这意味着继承类不能覆盖该方法。
  • 也许吧,但我实际上想要 interiting 类来覆盖该方法。这实际上是原始代码的大部分要点。我可能需要重写示例,但会更长。

标签: php inheritance object methods parent


【解决方案1】:

要让它工作,你可以像这样修改你的 base_class:

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

 function inherit_this() {
    $this->do_something();
 }
}

然后你的top_clas会调用你的基类的inherit_this(),但是会有一个递归:top_class的do_something()调用$this->inherit_this(),而在base_class中你又调用了$this->do_something() (在您的基类中 $this 将引用您的 top_class)。因此,您将一遍又一遍地调用inherit_this()。

您应该重命名方法以防止这种情况发生。

更新

如果您希望 base_class inherit_this() 打印“base_class::do_something”,您可以像这样修改您的 base_class:

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

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

}

在这种情况下,您对 base_class 方法 do_something() 进行静态调用。输出为top_class::do_something() base_class::do_something()

更新 2

关于您的评论,您可以像这样修改您的 base_class:

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

你得到 $this 的父类,然后调用该方法。输出将是:top_class::do_something() middle_class::do_something()

【讨论】:

  • 想要是让它调用middle_class::do_something(),因为真正的代码在层次结构的每一层以不同的方式操作数据,我想要遍历层次结构一直到基层,而无需在每个级别重新实现 inherit_this()。
  • 这似乎确实有效,但我无法摆脱它可能会在以后引入一些难以发现的错误的感觉,因为它实际上将 middle_class::do_something() 作为静态方法调用,不是 $this 的方法。 $this 仍然设置,只是因为 PHP 的奇怪范围。我还没有想到它会崩溃的例子,但我很紧张。我认为call_user_func(array($this, get_parent_class($this) . "::do_something")) 可能会更好,但我也感觉不好。
  • 嗯,是的,php 中的 OOP 通常有点奇怪...出于调试目的,您可以在类中实现一个特殊的调试标志并使用一些“魔术常量”。有了他们,通常很容易找出发生了什么。查看此页面以获取更多信息:davidwalsh.name/php-magic-constants
  • 经过进一步思考,我意识到此方法不适用于由 top_class 的祖先类定义的方法调用 inherit_this() 的情况。例如,如果它被middle_class::do_something() 调用,则会导致无限循环。然而,我确实设计了一个涉及debug_backtrace() (yuck) 的解决方案,这似乎可行。我在单独的答案中写了详细信息和更长的示例。
【解决方案2】:

我不太确定我理解你为什么要这样做。但我猜你做不到。我知道您将能够创建一个 middle_class2 并能够从中继承,然后它将是 middle_class2 而不是您调用的 middle_class 的 dosomething?!

所以我猜你需要创建

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

在中产阶级中。

我想过一个 get_class($this)::parent::do_something().. 但这没有用。

只是为了确定.. 你想调用 middle_class::do_something() 对吗?

【讨论】:

  • 正确,可以完全访问$this的属性和方法
【解决方案3】:

首先我要对 grrbrr404 说“谢谢”。他给了我一些想法,让我开始朝着正确的方向前进。

我最终确定的解决方案如下:

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

它并不漂亮(我特别讨厌为此调用debug_backtrace()),但它会将对象上下文设置为$this,并处理从对象层次结构中间某处的方法调用该方法的情况。

对于那些发现我的示例令人困惑和/或想知道“您为什么要这样做?”的人。很抱歉,并提供以下附加示例,希望它更能说明问题并更接近原始问题。它要长得多,但希望能说明为什么我关心正确设置 $this,也说明为什么我不能硬编码任何特定的类名或使用 $this->method()。避免无限循环始终是我的首要任务。 :-)

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

我试图避免重复“checkType()”函数,但即使在层次结构变得任意大时仍能提供正确的行为。

当然,更优雅的解决方案是最受欢迎的。

【讨论】:

    【解决方案4】:
    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();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-14
      • 1970-01-01
      • 1970-01-01
      • 2021-08-02
      • 2017-07-20
      • 2016-08-15
      • 1970-01-01
      相关资源
      最近更新 更多