php 面向对象|有没有办法使用父方法调用继承的方法?

f1tvaqid  于 2023-02-28  发布在  PHP
关注(0)|答案(1)|浏览(117)

下面是一个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::
任何想法都将受到高度赞赏。谢谢!

esyap4oy

esyap4oy1#

这里有3个简单的方法:
1.您可以在调用方中创建A的新示例:

public function caller(){
    var_dump ('Using $this.. '. $this->mainMethod());
    $newA = new A();
    var_dump ('Using parent.. '. $newA->mainMethod());
}

那么A不被扩展,主方法将调用A的子方法.
你在A的主方法中创建一个A的新示例,条件是设置了一个参数。就像在1中,在$newA示例中,没有被B扩展的A将调用A的子方法。

public function mainMethod(bool $forceA = false){
    if($forceA){
        $newA = new A();
        return $newA->subMethod();
    } else {
        return 'calling ' . $this->subMethod();
    }
}

另一种方法是在Bx 1 m1n1x参数中的subMethod中添加一个布尔参数,如果为真,则调用parent::subMethod

protected function subMethod(bool $callParent = false) {
    return $callParent?parent::subMethod():"B::subMethod";
}

当$callParent为真时,B仍然会被调用,但是B::subMethod会直接调用A::subMethod。
然后,您只需在mainMethod中传递$callParent参数:

public function mainMethod(bool $callParent = false){
    return 'calling ' . $this->subMethod($callParent);
}

出于兼容性的原因,您还应该将参数添加到A的subMethod中,并且在那里它将不被使用,以便在调用A的subMethod时设置参数的情况下不会创建错误。(如果您创建了A的示例而没有进行扩展,或者子类不包含subMethod,则会发生这种情况)。

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时,它就正确了,所以这是一条人行道,混乱的坑洞就等着你掉进去,让你发疯。

相关问题