variable tipos que publicas programacion privados privadas privada metodos funciones entre diferencia php override private visibility

php - tipos - Comportamiento extraño al anular métodos privados



tipos de metodos en php (3)

Considere la siguiente pieza de código:

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();

Ahora, cambiando la visibilidad del método m() , obtengo:
( + para public , - para 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 parece comportarse como public ).

Esperaba que todo se comporte como lo hace cuando ambos se declaran public . Pero aunque foo->call() y bar->callbar() son esencialmente lo mismo, producen resultados diferentes dependiendo de la visibilidad de m() en foo y bar . ¿Por qué pasó esto?


Heredar / anular métodos privados

En PHP, los métodos (incluidos los privados) en las subclases son:

  • Copiado Se mantiene el alcance de la función original.
  • Sustituido ("anulado", si lo desea).

Puedes ver esto con este código:

<?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();

Ahora, si reemplaza el método privado, su nuevo alcance no será A, será B y la llamada fallará porque A::callH() ejecuta en el alcance 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''

Métodos de llamada

Aquí las reglas son las siguientes:

  • Busque en la tabla de métodos de la clase real del objeto (en su caso, bar ).
    • Si esto da lugar a un método privado :
      • Si el alcance donde se definió el método es el mismo que el alcance de la función que llama y es el mismo que la clase del objeto, utilícelo.
      • De lo contrario, busque en las clases primarias un método privado con el mismo alcance que el de la función de llamada y con el mismo nombre.
      • Si no se encuentra ningún método que satisfaga uno de los requisitos anteriores, falle.
    • Si esto produce un método público / protegido :
      • Si el alcance del método está marcado como cambiado, es posible que hayamos anulado un método privado con un método público / protegido. Entonces, en ese caso, y si, adicionalmente, hay un método con el mismo nombre que es privado tal como se define para el alcance de la función de llamada, use ese en su lugar.
      • De lo contrario, utilice el método encontrado.

Conclusión

  1. (Ambos privados) Para bar->call() , el alcance de la call es foo . Llamar a $this->m() provoca una búsqueda en la tabla de métodos de la bar para m , produciendo una bar::m() privada bar::m() . Sin embargo, el alcance de bar::m() es diferente del alcance de la llamada, que foo . El método foo:m() se encuentra al atravesar la jerarquía y se usa en su lugar.
  2. (Privado en foo , público en bar ) El alcance de la call sigue siendo foo . La búsqueda produce una bar::m() pública bar::m() . Sin embargo, su ámbito está marcado como cambiado, por lo que se realiza una búsqueda en la tabla de funciones del ámbito de llamada foo para el método m() . Esto produce un método privado foo:m() con el mismo alcance que el alcance de llamada, por lo que se usa en su lugar.
  3. No hay nada que ver aquí, error porque la visibilidad se redujo.
  4. (Ambos públicos) El alcance de la call sigue siendo foo . La búsqueda produce una bar::m() pública bar::m() . Su alcance no está marcado como cambiado (ambos son públicos), por lo que se utiliza bar::m() .

Según el manual de PHP:

Los miembros declarados como privados solo pueden ser accedidos por la clase que define al miembro.

http://www.php.net/manual/en/language.oop5.visibility.php

EDITAR

dan resultados diferentes dependiendo de la visibilidad de m () en foo y bar. ¿Por qué pasó esto?

Si m() en foo es público, es anulable. Cuando este es el caso, m() de la bar anula m() en foo .


Un método privado no es anulable, ya que un método privado no es visible incluso para sus subclases. Definir un método como protegido significa que no es visible fuera de la propia clase o sus subclases.

Si tiene un método que desea usar de su clase principal pero desea que los niños puedan modificar su comportamiento y no quiere que este método esté disponible externamente, use protected . Si desea una funcionalidad en su clase principal que no pueda ser modificada de ninguna manera por subclases, defina el método como private .

EDITAR: para aclarar aún más, si tiene dos métodos con el mismo nombre en un padre y una subclase, y estos métodos se definen como privados, esencialmente el método de la subclase no tiene absolutamente ninguna relación con el método principal. Como se indicó, un método privado es COMPLETAMENTE INVISIBLE para la subclase.

Considera esto:

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(); } }

Llamando a $bar->callz() ; producirá un ERROR, porque z no existe en la subclase en absoluto, ni siquiera como un método heredado.