提问人:NullUserException 提问时间:9/21/2010 最后编辑:NullUserException 更新时间:9/21/2010 访问量:21016
重写私有方法时的奇怪行为
Strange behavior when overriding private methods
问:
请考虑以下代码段:
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();
现在,更改方法的可见性,我得到:
( for , form()
+
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
我本来以为一切都会像两者都声明时那样运行.但是,尽管 和本质上是一回事,但它们会产生不同的结果,具体取决于 in 和 的可见性。为什么会这样?public
foo->call()
bar->callbar()
m()
foo
bar
答:
私有方法不可重写,因为私有方法甚至对其子类也不可见。将方法定义为受保护意味着它在类本身或其子类之外不可见。
如果要从父类使用方法,但希望子类能够修改其行为,并且不希望此方法在外部可用,请使用 .如果希望父类中的功能不能被子类以任何方式修改,请将方法定义为 。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();
}
}
叫;将产生一个 ERROR,因为 z 根本不存在于子类中,甚至不作为继承的方法。$bar->callz()
评论
bar->callbar()
m()
foo
public
bar
m()
bar
bar->call()
bar->m()
根据PHP手册:
被声明为私人的会员只能 由定义 成员。
http://www.php.net/manual/en/language.oop5.visibility.php
编辑
它们产生不同的结果,具体取决于 关于 foo 中 m() 的可见性和 酒吧。为什么会这样?
如果 in 是公共的,则它是可覆盖的。在这种情况下,从 中的覆盖。m()
foo
m()
bar
m()
foo
继承/重写私有方法
在 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
- 如果这会产生私有方法:
- 如果定义方法的作用域与调用函数的作用域相同,并且与对象的类相同,请使用它。
- 否则,请在父类中查找与调用函数的作用域相同且名称相同的私有方法。
- 如果未找到满足上述要求之一的方法,则失败。
- 如果这会产生一个公共/受保护的方法:
- 如果方法的范围被标记为已更改,我们可能已使用公共/受保护方法重写了私有方法。因此,在这种情况下,如果另外有一个方法与为调用函数的作用域定义的名称相同,则改用该方法。
- 否则,请使用 found 方法。
- 如果这会产生私有方法:
结论
- (均为私人)对于 ,的作用域是 。调用会在 for 的方法表中引发查找,从而生成一个私有的 .但是,的作用域与调用作用域不同,调用作用域为 .该方法在遍历层次结构时找到,并改用。
bar->call()
call
foo
$this->m()
bar
m
bar::m()
bar::m()
foo
foo:m()
- (私人在,公共在)的范围仍然是 。查找会生成一个公共 .但是,其作用域被标记为已更改,因此在方法的调用作用域的函数表中进行了查找。这将生成一个与调用范围具有相同作用域的私有方法,因此将改用该方法。
foo
bar
call
foo
bar::m()
foo
m()
foo:m()
- 这里没什么可看的,错误是因为能见度降低了。
- (均为公开)的范围仍然是 。查找会生成一个公共 .它的作用域未标记为已更改(它们都是公共的),因此被使用。
call
foo
bar::m()
bar::m()
评论