PHP - 重新定义方法并调用相同方法的祖先版本

时间:2012-09-05 17:42:45

标签: php inheritance

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

这是一个简短的例子:

// 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 个答案:

答案 0 :(得分: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();

将打印(按照预期,见this demo):

ABC

挑战是从输出中删除B,实际上只执行A的{​​{1}}和foo()的{​​{1}}。所以,让我们进入Reflection并抓住C的{​​{1}}方法,然后在foo()的对象上调用它。现在考虑A的替代定义:

foo()

现在,您只能获得输出(如this demo中所示):

C

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

答案 1 :(得分:2)

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

爸爸>妈妈>宝贝>婴儿,其中方法 sayWhat()&实例变量 $ el 在每个后代类中被覆盖,您可以调用任何祖先说出来自Infant的什么方法,并访问不同的祖先默认属性值:

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

输出:

  

什么是PAPA! El:[MamaEl]

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

答案 2 :(得分:0)

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

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

然后在myClass中更改你的doSomething方法,如下所示:

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

答案 3 :(得分:0)

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

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