Intereting Posts
Как получить электронную почту и обработать ее в веб-приложении Вернуть результаты поиска изображений Google в HTML с помощью PHP Как вы подключаетесь к нескольким базам данных MySQL на одной веб-странице? Кэш Symfony 2.7: команда clear проверяет каждое подключение к базе данных Создание WSDL при использовании собственного класса SOAP PHP? Подпись Версия 4 Процесс подписания в PHP для доступа к конечной точке шлюза API как разрешить дублирование ключей в php-массиве if (! empty ($ _ POST)) не работает multibyte strtr () -> mb_strtr () Кодовая кодировка CodeIgniter и поддержка UTF-8 параметр, уже выбранный при загрузке страницы в выпадающем списке, а также changeble Какие проблемы безопасности могут возникнуть при представлении phpinfo () конечным пользователям? Использование usort в php для сортировки массива объектов? Преобразование строки запроса в ассоциативный массив Используйте openssl_encrypt для замены Mcrypt для шифрования 3DES-ECB

Странное поведение при переопределении частных методов

Рассмотрим следующий фрагмент кода:

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 . Почему это происходит?

Solutions Collecting From Web of "Странное поведение при переопределении частных методов"

Наследование / переопределение частных методов

В 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 ).
    • Если это дает частный метод :
      • Если область, в которой был определен метод, совпадает с областью действия вызывающей функции и совпадает с классом объекта, используйте ее.
      • В противном случае просмотрите родительские классы для частного метода с той же областью действия, что и вызывающая функция и с тем же именем.
      • Если не найден какой-либо метод, удовлетворяющий одному из вышеуказанных требований, сбой.
    • Если это дает общедоступный / защищенный метод :
      • Если область действия метода отмечена как измененная, мы можем переопределить частный метод с помощью общедоступного / защищенного метода. Таким образом, в этом случае, и если, кроме того, существует метод с тем же именем, что и private, как определено для области вызывающей функции, используйте это вместо этого.
      • В противном случае используйте найденный метод.

Вывод

  1. (Both private) Для bar->call() объем call foo . Вызов $this->m() вызывает поиск в таблице методов bar для m , что дает частный bar::m() . Однако область bar::m() отличается от области вызова, которая foo . Метод foo:m() найден при обходе иерархии и используется вместо этого.
  2. (Закрыто в foo , public в bar ). Объем call по-прежнему foo . В результате поиска создается публичная bar::m() . Однако его область помечена как измененная, поэтому поиск выполняется в таблице функций вызывающей области foo для метода m() . Это дает частный метод foo:m() с той же областью действия, что и область вызова, поэтому используется вместо этого.
  3. Здесь ничего не видно, потому что видимость была снижена.
  4. (Оба общедоступны). Объем 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 .