5

我想重新定义一个方法,并调用它的祖先版本,而不是我父母的。

这是一个简短的例子:

// This class is autogenerated and I am not supposed to modify it.
class myParent extends myGrandparent {

  function doSomething() {
    doA();
    doB();
    doC();
    parent::doSomething();
  }

}

// Here is my code
class myClass extends myParent {

  function doSomething() {
    // doA();    // I don't want to do A anymore.
    // doB();    // Neither B.
    doC();       // But I want to keep doing C.
    parent::doSomething();      // OOPS!!  This does A and B (and C again)!
  }

}

如何直接调用 myGrandparent 的方法,而不是 myParent 的?

4

4 回答 4

4

我不同意“你不能这样做”的论点——你可以Reflection来做到这一点。

考虑以下类结构:

class A { 
    function foo() { 
        echo 'A'; 
    }
}

class B extends A { 
    function foo() { 
        parent::foo();  
        echo 'B'; 
    }
}

class C extends B { 
    function foo() { 
        parent::foo();
        echo 'C'; 
    }
}

用这个初始化时:

$o = new C;
$o->foo();

将打印(如预期的那样,在这个演示中看到):

ABC

挑战是B从输出中删除 's ,有效地只执行A'sfoo()C's foo()。所以,让我们进入 Reflection 和 grabA的方法,然后在的对象foo()上调用它。C现在考虑这个替代定义C

class C extends B { 
    function foo() { 
        $ref = new ReflectionClass( $this);
        $parent = $ref->getParentClass()->getParentClass();
        $parent->getMethod( 'foo')->invoke( $this);
        echo 'C'; 
    }
}

现在,您只会得到输出(如本演示所示):

AC

这是否是“良好做法”,取决于 OP。我想我已经证明可以“跳过”B函数的实现并从孙子类调用祖父函数。

于 2012-09-05T18:06:50.870 回答
2

不确定用例是什么,但除非我误解了问题/问题(很可能),否则您完全可以调用任何任意祖先(公共或受保护)方法,无论其被覆盖多少次,甚至默认任何祖先成员属性(公共或受保护)的值,即使它也已被覆盖。例如,对于类层次结构:

Papa > Mama > Baby > Infant,其中方法sayWhat()和实例变量$el在每个后代类中都被覆盖,您可以从 Infant 调用任何祖先 sayWhat 方法,并访问不同的祖先默认属性值:

class Papa {
  protected $el = 'PapaEl';
  protected function sayWhat($className = null) {
    if (!$className) {
      $className = get_class($this);
    }
    $classVars = get_class_vars($className);
    $localEl = $classVars['el'];
    echo "<h2>What is PAPA!. El: [$localEl]</h2>";
  }
}

class Mama extends Papa {
  protected $el = 'MamaEl';
  protected function sayWhat() {
    echo "<h2>What is MAMA! El: [$this->el]</h2>";
  }
}

class Baby extends Mama {
  protected $el = 'BabyEl';
  protected function sayWhat() {
    echo "<h2>What is Lil' Baby!! El: [$this->el]</h2>";
  }
}

class Infant extends Baby {
  protected $el = 'InfantEl';
  protected function sayWhat($className) {
    Papa::sayWhat($className);
  }

  public function mySayWhat($className) {
    $this->sayWhat($className);
  }
}
$i = new Infant();
$i->mySayWhat('Mama');

输出:

什么是爸爸!艾尔:[妈妈艾尔]

不确定它有什么价值,但如果有人有要求,它似乎非常可行......

于 2014-06-08T17:21:24.330 回答
0

你真的不能。您需要直接从 myGrandParent 扩展,或者需要重新编写 MyParent 中的逻辑以提供对 myGrandParents 方法的“直通”访问。例如,您可以像这样在 myParent 上创建一个方法:

function doSomethingGrandparent() {
    parent::doSomething();
}

然后像这样更改 myClass 中的 doSomething 方法:

function doSomething() {
    parent::doSomethingGrandparent();
}
于 2012-09-05T17:48:13.433 回答
0

答案是否定的,你不能。子级重新声明该方法的父级功能并完全覆盖它。

我认为静态方法是必需的,因为您不能将 parent:: 关键字链接到“祖父母”类,因此 parent::parent::foo( ) 不起作用。

于 2012-09-05T17:54:03.743 回答