覆盖私有方法时的奇怪行为 [英] 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();
现在,更改m()
方法的可见性,我得到:
(对于public
,+
,对于private
,-
)
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
的行为类似于public
).
我期望所有的行为都与声明为public
时的行为相同.但是,尽管foo->call()
和bar->callbar()
本质上是同一件事,但是根据foo
和bar
中m()
的可见性,它们会产生不同的结果.为什么会这样?
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?
推荐答案
继承/覆盖私有方法
在PHP中,子类中的方法(包括私有方法)为:
Inheriting/overriding private methods
In PHP, methods (including private ones) in the subclasses are either:
- 已复制;保持原始功能的范围.
- 已替换(如果需要,可以覆盖").
您可以通过以下代码看到此内容:
You can see this with this code:
<?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
中运行:
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 scope 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'
调用方法
这里的规则如下:
Calling methods
Here the rules are as follows:
- 查看对象的 actual class 的方法表(在您的情况下为
bar
).- 如果这产生了私有方法:
- 如果定义方法的范围与调用函数的范围相同并且与对象的类相同,请使用它.
- 否则,请在父类中查找一个私有方法,该私有方法的范围与调用函数之一的范围相同,并且名称相同.
- 如果未找到满足上述要求之一的方法,则失败.
- Look in the method table of the actual class of the object (in your case,
bar
).- If this yields a private method:
- If the scope where the method was defined is the same as the scope of the calling function and is the same as the class of the object, use it.
- Otherwise, look in the parent classes for a private method with the same scope as the one of the calling function and with the same name.
- If no method is found that satisfies one of the above requirements, fail.
- 如果方法的范围被标记为已更改,则我们可能已用公共/受保护的方法覆盖了私有方法.因此,在这种情况下,如果另外还有一个方法的名称与为调用函数的作用域定义的私有名称相同,请改用该方法.
- 否则,请使用找到的方法.
- (均为私有)对于
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()
.
- (Both private) For
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. - (Private in
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. - Nothing to see here, error because visibility was lowered.
- (Both public) The scope of
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.
这篇关于覆盖私有方法时的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- If this yields a private method:
- 如果这产生了私有方法: