覆盖私有方法时的奇怪行为
考虑以下代码:
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
时一样。但是,尽管 foo->call()
和 bar->callbar()
本质上是同一件事,但它们会根据 m 的可见性产生不同的结果()
在 foo
和 bar
中。为什么会出现这种情况?
Consider the following piece of code:
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();
Now, changing the visibility of the m()
method, I get:
(+
for public
, -
for 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
seems to behave like public
).
I was expecting everything to behave like it does when both are declared public
. But although foo->call()
and bar->callbar()
are essentially the same thing, they yield different results depending on the visibility of m()
in foo
and bar
. Why does this happen?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
继承/重写私有方法
在 PHP 中,子类中的方法(包括私有方法)可以是:
您可以通过以下代码看到这一点:
现在,如果您重写私有方法,其新作用域将不是 A,而是 B,并且调用将失败,因为
A::callH()
运行于范围A
:调用方法
这里的规则如下:
bar
)。结论
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()
。Inheriting/overriding private methods
In PHP, methods (including private ones) in the subclasses are either:
You can see this with this code:
Now if you override the private method, its new scope will not be A, it will be B, and the call will fail because
A::callH()
runs in scopeA
:Calling methods
Here the rules are as follows:
bar
).Conclusion
bar->call()
, the scope ofcall
isfoo
. Calling$this->m()
elicits a lookup in the method table ofbar
form
, yielding a privatebar::m()
. However, the scope ofbar::m()
is different from the calling scope, whichfoo
. The methodfoo:m()
is found when traversing up the hierarchy and is used instead.foo
, public inbar
) The scope ofcall
is stillfoo
. The lookup yields a publicbar::m()
. However, its scope is marked as having changed, so a lookup is made in the function table of the calling scopefoo
for methodm()
. This yields a private methodfoo:m()
with the same scope as the calling scope, so it's used instead.call
is stillfoo
. The lookup yields a publicbar::m()
. Its scope isn't marked as having changed (they're both public), sobar::m()
is used.私有方法不可重写,因为私有方法甚至对其子类也是不可见的。将方法定义为受保护意味着该方法在类本身或其子类之外不可见。
如果您想在父类中使用某个方法,但希望子类能够修改其行为,并且不希望该方法在外部可用,请使用
protected
。如果您希望父类中的功能不能被子类以任何方式修改,请将该方法定义为private
。编辑:进一步澄清,如果父类和子类中有两个同名的方法,并且这些方法被定义为私有方法,则本质上子类方法与父类方法完全没有关系。如前所述,私有方法对于子类来说是完全不可见的。
考虑一下:
调用
$bar->callz()
;将产生错误,因为 z 根本不存在于子类中,即使作为继承方法也不存在。A private method is not overridable, as a private method is not visible even to its subclasses. Defining a method as protected means it is not visible outside of the class itself or its subclasses.
If you have a method that you want to use from your parent class but want children to able to modify its behaviour, and don't want this method available externally, use
protected
. If you want functionality in your parent class that cannot be modified in any way by subclasses, define the method asprivate
.EDIT: to clarify further, if you have two methods with the same name in a parent and subclass, and these methods are defined as private, essentially the subclass method has absolutely no relation to the parent method. As stated, a private method is COMPLETELY INVISIBLE to the subclass.
Consider this:
Calling
$bar->callz()
; is going to produce an ERROR, because z does not exist in the subclass at all, not even as an inherited method.根据 PHP 手册:
http://www.php.net/manual/en/language。 oop5.visibility.php
编辑
如果
foo
中的m()
是公共的,则它是可重写的。在这种情况下,bar
中的m()
会覆盖foo
中的m()
。According to the PHP manual:
http://www.php.net/manual/en/language.oop5.visibility.php
EDIT
If
m()
infoo
is public, it is overridable. When this is the casem()
frombar
overridesm()
infoo
.