下面是一个PHP代码片段来说明我的问题:
<?php
class A {
protected function subMethod() {
return "A::subMethod";
}
public function mainMethod(){
return 'calling ' . $this->subMethod();
}
}
class B extends A {
protected function subMethod() {
return "B::subMethod";
}
public function caller(){
var_dump ('Using $this.. '. $this->mainMethod());
var_dump ('Using pareint.. '. parent::mainMethod());
}
}
$b = new B();
$b->caller();
输出(实际行为):
"Using $this.. calling B::subMethod"
"Using pareint.. calling B::subMethod"
期望的行为
"Using $this.. calling B::subMethod"
"Using pareint.. calling A::subMethod"
当使用parent::mainMethod()
时,它仍然使用B::subMethod
,因为mainMethod
中的$this
仍然引用调用函数的对象$b
。我知道它应该是这样工作的,但我不知道如何使用依赖于父类子方法的父类方法而不必重写主方法。我不想重写它,因为我有很多子类和重写函数意味着我将不得不添加多余的代码,在父和子方法中基本相同,除了使用$this
而不是parent::
。
任何想法都将受到高度赞赏。谢谢你!
有三个简单的方法:
1。您可以在调用者中创建a的新实例:
public function caller(){
var_dump ('Using $this.. '. $this->mainMethod());
$newA = new A();
var_dump ('Using parent.. '. $newA->mainMethod());
}
则A没有被扩展,主方法将调用A的subMethod
在参数设置的条件下,在a的Main Method中创建a的新实例。像在1中一样,在$newA实例中没有被B扩展,B将调用A的subMethod
public function mainMethod(bool $forceA = false){
if($forceA){
$newA = new A();
return $newA->subMethod();
} else {
return 'calling ' . $this->subMethod();
}
}
另一种方法是为B中的$callParent
参数中的subMethod
添加一个布尔参数,如果它为真,则调用parent::subMethod
。
protected function subMethod(bool $callParent = false) {
return $callParent?parent::subMethod():"B::subMethod";
}
B仍然会被调用,但是当$callParent为true时,B::subMethod会直接调用A::subMethod。
然后通过mainMethod:
中的$callParent
参数public function mainMethod(bool $callParent = false){
return 'calling ' . $this->subMethod($callParent);
}
出于兼容性原因,您应该将参数也添加到A的子方法中,并且在那里它将未被使用,以便在调用A的子方法时设置参数时不会产生错误(如果您创建A的实例而不扩展或子类不包含子方法,则会发生这种情况)。
protected function subMethod(bool $callParent = false) {
return "A::subMethod";
}
调用者在解决方案2和3中看起来是一样的。
public function caller(){
var_dump ('Using $this.. '. $this->mainMethod());
var_dump ('Using parent.. '. $this->mainMethod(true));
}
让我们庆祝一下,用溶液3作为基础。
如果D扩展了C, C扩展了B, B扩展了A,那么它可能会变得复杂/混乱,当你想在一个类中调用B或其他东西时,假设C不包含subMethod
,但D包含。
为了能够在中间调用一些东西,你需要从布尔值切换到整数,然后再往上一级。
public function mainMethod(int $callParentLevel = 0){
return 'calling ' . $this->subMethod($callParentLevel);
}
protected function subMethod(int $callParentLevel = 0) {
return $callParentLevel>=1?parent::subMethod($callParentLevel-1):"D::subMethod";
}
到目前为止一切顺利。看起来简单。
现在你想得到D和b的结果,这意味着两级以上,对吗?
D中的调用者现在:
public function caller(){
var_dump ('Using $this.. '. $this->mainMethod()); // As expectet, it gives you the D
var_dump ('Using parent.. '. $this->mainMethod(2)); // Question: would you get the B job done, or is what you receive A...
}
哎呀,你收到的是A,因为当C不包含subMethod
时,就像我在这部分开头写的那样,那么从D到B就是1。但当C含有subMethod
时,它是正确的。所以这是一条充满混乱的人行道,等着你掉进去,把你逼疯。