Рассмотрим следующий фрагмент кода:
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 .