Рассмотрим следующий фрагмент кода:
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
. Почему это происходит?
В 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
для m
, что дает частный bar::m()
. Однако область bar::m()
отличается от области вызова, которая foo
. Метод foo:m()
найден при обходе иерархии и используется вместо этого. foo
, public в bar
). Объем call
по-прежнему foo
. В результате поиска создается публичная bar::m()
. Однако его область помечена как измененная, поэтому поиск выполняется в таблице функций вызывающей области foo
для метода m()
. Это дает частный метод foo:m()
с той же областью действия, что и область вызова, поэтому используется вместо этого. call
по-прежнему foo
. В результате поиска создается публичная bar::m()
. Его область не отмечена как измененная (они оба являются общедоступными), поэтому используется bar::m()
. Закрытый метод не является переопределяемым, поскольку частный метод не отображается даже в его подклассах. Определение защищенного метода означает, что оно не видно вне самого класса или его подклассов.
Если у вас есть метод, который вы хотите использовать из родительского класса, но хотите, чтобы дети могли изменять его поведение и не хотите, чтобы этот метод был доступен извне, используйте protected
. Если вы хотите, чтобы функциональность в родительском классе не могла быть каким-либо образом изменена подклассами, определите метод как private
.
EDIT: уточнить, если у вас есть два метода с тем же именем в родительском и подклассе, и эти методы определяются как частные, по существу метод подкласса абсолютно не имеет отношения к родительскому методу. Как указано, частный метод ПОЛНОСТЬЮ НЕВИДИМО для подкласса.
Учти это:
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 вообще не существует в подклассе, даже не в качестве унаследованного метода.
Согласно руководству PHP:
Участникам, объявленным как private, может быть доступен только класс, определяющий участника.
http://www.php.net/manual/en/language.oop5.visibility.php
РЕДАКТИРОВАТЬ
они дают разные результаты в зависимости от видимости m () в foo и bar. Почему это происходит?
Если m()
в foo
является общедоступным, оно является допустимым. Когда это так, m()
от bar
переопределяет m()
в foo
.