考虑以下代码:
class foo {
private function m() {
echo 'foo->m() ';
}
public function call() {
$this->m();
}
}
class bar extends foo {
private function m() {
echo 'bar->m() ';
}
public function callbar() {
$this->m();
}
}
$bar = new bar;
$bar->call();
$bar->callbar();
现在,更改m()
方法的可见性,我得到:
(+
为public
,-
为private
Visibility bar->call() bar->callbar()
======================================================
-foo->m(), -bar->m() foo->m() bar->m()
-foo->m(), +bar->m() foo->m() bar->m()
+foo->m(), -bar->m() ERROR ERROR
+foo->m(), +bar->m() bar->m() bar->m()
(protected
似乎表现得像public
)。
我期待一切都像宣布public
时的行为一样。但是,虽然foo->call()
和bar->callbar()
基本上是相同的,但它们会产生不同的结果,具体取决于m()
和foo
中bar
的可见性。为什么会这样?
答案 0 :(得分:25)
在PHP中,子类中的方法(包括私有方法)是:
您可以使用以下代码查看:
<?php
class A {
//calling B::h, because static:: resolves to B::
function callH() { static::h(); }
private function h() { echo "in A::h"; }
}
class B extends A {
//not necessary; just to make explicit what's happening
function callH() { parent::callH(); }
}
$b = new B;
$b->callH();
现在,如果你覆盖私有方法,它的新范围将不是A,它将是B,并且调用将失败,因为A::callH()
在范围A
中运行:
<?php
class A {
//calling B::h, because static:: resolves to B::
function callH() { static::h(); }
private function h() { echo "in A::h"; }
}
class B extends A {
private function h() { echo "in B::h"; }
}
$b = new B;
$b->callH(); //fatal error; call to private method B::h() from context 'A'
这里的规则如下:
bar
)。
bar->call()
,call
的范围为foo
。调用$this->m()
会在bar
的{{1}}方法表中引发查找,从而产生私有m
。但是,bar::m()
的范围与调用范围不同,bar::m()
。在遍历层次结构时会找到方法foo
,而不是使用它。foo:m()
中的私人,foo
中的公开)bar
的范围仍为call
。查找产生公共foo
。但是,其范围标记为已更改,因此在方法bar::m()
的调用范围foo
的函数表中进行查找。这会产生一个私有方法m()
,其范围与调用范围相同,因此可以使用它。foo:m()
的范围仍为call
。查找产生公共foo
。其范围未标记为已更改(它们都是公开的),因此使用bar::m()
。答案 1 :(得分:13)
私有方法不可覆盖,因为私有方法甚至对其子类也不可见。将方法定义为受保护意味着它在类本身或其子类之外是不可见的。
如果您要在父类中使用某个方法,但希望子级能够修改其行为,并且不希望外部使用此方法,请使用protected
。如果您希望子类中的功能无法以任何方式由子类进行修改,请将方法定义为private
。
编辑:进一步澄清,如果在父类和子类中有两个同名的方法,并且这些方法被定义为私有,本质上子类方法与父类完全没有关系方法。如上所述,私有方法完全不可见于子类。
考虑一下:
class foo {
private function m() {
echo 'foo->m() ';
}
private function z() { echo "foo->z();"; }
public function call() {
$this->m();
}
}
class bar extends foo {
private function m() {
echo 'bar->m() ';
}
public function callbar() {
$this->m();
}
public function callz()
{
$this->z();
}
}
致电$bar->callz()
;将产生一个ERROR,因为z根本不存在于子类中,甚至不作为继承方法。
答案 2 :(得分:3)
根据PHP手册:
宣布为私人的会员可能只是 由定义的类访问 会员。
http://www.php.net/manual/en/language.oop5.visibility.php
修改
它们会产生不同的结果 关于foo和f中m()的可见性 酒吧。为什么会这样?
如果m()
中的foo
是公开的,则可以覆盖。如果是m()
来自bar
的{{1}}覆盖m()
中的foo
。