PHP手册可见性示例混淆

6

我从php手册的一个例子中感到困惑,它涉及到可见性。以下是示例:

class Bar {
    public function test() {
        $this->testPrivate();
        $this->testPublic();
    }
    public function testPublic() {
        echo "Bar::testPublic\n";
    }
    private function testPrivate() {
        echo "Bar::testPrivate\n";
    }
}
class Foo extends Bar {
    public function testPublic() {
        echo "Foo::testPublic\n";
    }
    private function testPrivate() {
        echo "Foo::testPrivate\n";
    }
}
$myFoo = new foo();
$myFoo->test();  
?>

http://www.php.net/manual/zh/language.oop5.visibility.php

以下是示例输出:

Bar::testPrivate 
Foo::testPublic

请问这是如何发生的?
为什么两个testPublic()都没有被调用?
我在Bar类的构造函数中放置了一个var_dump($this)。它打印出object(Foo)[1]。我知道私有属性可以在同一个类中被调用。
那么,"Bar::testPrivate"是如何被调用的呢?
6个回答

6
那么"Bar::testPrivate"是如何被调用的?
当你调用$myFoo->test()时,它在Bar的上下文中运行代码,因为Foo类没有覆盖它。
Bar::test()内部,当调用$this->testPrivate()时,解释器会首先查找Foo,但该方法是私有的(而且不能从Bar调用后代类的私有方法),所以它向上一级查找直到找到合适的方法;在这种情况下,它将是Bar::testPrivate()
相反,当调用$this->testPublic()时,解释器立即在Foo中找到一个合适的方法并运行它。
编辑
为什么两个testPublic()都没有被调用?
当你运行$this->testPublic()时,只有一个方法被调用,最远的一个(就距离基类而言)。
如果Foo::testPublic()还需要执行父类的实现,则应在该方法内编写parent::testPublic()

3
为什么test()(即Bar类的test()方法)不能调用Foo类的testPrivate()方法呢?因为它是私有的,就像你不希望父母触碰孩子的私密部位一样。 - NullUserException
我想,关于testPublic()的混淆部分是因为PHP执行替换覆盖而不是细化覆盖。这意味着除非您明确要求它这样做(例如:parent::testPublic();),否则PHP不会在子类中调用父类的方法。 - NullUserException
@Jack 谢谢兄弟。你解释得非常清楚。现在我明白了要点。因为 $this 指的是 foo,所以我以为应该调用 Foo 类的私有函数。这就是我困惑的地方。 - Namal

2

你的函数位于Bar类中,并使用魔术指针$this调用成员函数。

尝试将函数test()移到Foo类中,然后看看会发生什么。输出应该是:

Foo::testPrivate
Foo::testPublic

在你的示例中,调用了Bar的私有函数,因为它仅适用于该类。Foo类中没有test函数,因此Bar类的test函数无法访问它们。
然后,由于函数重载,调用了类Foo的公共函数而不是Bar的函数。
两个类都有同名函数,因此子类的函数更为重要。

1

Private并不意味着你不能调用它。它意味着你只能从当前类中调用它。 Public意味着你可以从任何类中调用它。

要调用Bar::testPrivate,请尝试以下操作:

$Bar->testPublic();

或者

parent::testPublic();

但是,您无法调用$Bar->testPrivate(),因为该方法是private


这并没有回答问题。 - NullUserException
抱歉,误解了问题。已修正。 - Terry Harvey

1

您打电话

$myFoo->test();

查看函数test

public function test() {
    $this->testPrivate();
    $this->testPublic();
}

当在Bar类(包括继承的类)的实例上调用此方法时,它会调用testPrivatetestPublic方法。

这些方法在Foo类中被覆盖,这意味着使用Foo类的方法。您始终可以调用基类的方法:

// in Foo
public function testPublic() {
    parent::testPublic();
    echo "Foo::testPublic\n";
}    

Bar::testPrivate 被调用是因为它是 private 的,并且没有被 Foo::testPrivate 覆盖。

更多信息请参见 此处此处


1

我猜用户'omega at 2093 dot es'的评论(http://www.php.net/manual/en/language.oop5.visibility.php#109324)描述的是同样的事情。 其中说到:“在父类中定义的方法不能访问从它们继承的类中定义的私有方法。但可以访问受保护的方法。”

在你的情况下,Bar::test()方法中的$this对象是Foo类型(您的var_dump证明了这一点)。由于Foo::testPrivate()方法是私有的,因此无法从父类Bar中访问,而唯一可以访问的方法是Bar::testPrivate()(尝试注释定义,你会得到致命错误)。这就是为什么第一个输出是Bar::testPrivate

$this->testPublic();调用Foo::testPublic()方法,因为$thisFoo类型,并且该方法被定义为公共的。

简单来说,私有方法只能从定义它们的类中访问。它们既不能从子类也不能从父类访问。
要使该方法可从子类或父类访问,请将其设置为受保护状态。例如,如果您在两个类中将testPrivate()方法设置为受保护状态,则它将打印Foo::testPrivate Foo::testPublic

0
类Foo继承自类Bar。然后调用了函数test,该函数在Bar中定义。在此函数中有两个调用。一个是调用类Bar中的公共函数,另一个是调用私有函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接