Inheriting/overriding private methods
In PHP, methods (including private ones) in the subclasses are either:
- Copied; the scope of the original function is maintained.
- Replaced (“overridden”, if you want).
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();
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:
- 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.
- If this yields a public/protected method:
- If the scope of the method is marked as having changed, we may have overridden a private method with a public/protected method. So in that case, and if, additionally, there’s a method with the same name that is private as is defined for the scope of the calling function, use that instead.
- Otherwise, use the found method.
- If this yields a private method:
Conclusion
- (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.