2012-10-05 58 views
12

He encontrado algo que parece ser un problema de herencia extraño en PHP.Herencia de PHP y visibilidad de miembro protegido

From the PHP manual:

miembros declarados protegidos sólo se puede acceder dentro de la clase sí mismo y por las clases heredadas y de los padres.

Para mí esto significa: A puede acceder a los miembros protegidos de B si A instanceof B o B instanceof A.

Sin embargo, si tanto A como B extienden Foo, y Foo tiene un constructor protegido que no se sobrescribe en B, entonces puedo crear una instancia de B desde A. Esto no tiene sentido para mí, porque A es no una instancia de B y B no es una instancia de A. También puedo llamar al método protegido $b->test() desde A, que ejecuta el método implementado en B. (Si B no redeclara test(), se ejecuta la implementación en Foo). Para mí, esto es aún más extraño porque no puedo crear una instancia de B desde A si B implementa directamente un constructor protegido. Parece extraño que no pueda acceder a un constructor protegido (también declarado en la clase principal) pero acceder a un método protegido (también declarado en la clase principal) no es problema.

Tenga en cuenta que obtengo el comportamiento esperado cuando uso una clase C que no extiende Foo. Si trato de crear una instancia B desde C, recibo un error fatal porque estoy tratando de acceder a un constructor protegido. Si agrego un constructor público a B, es posible crear una instancia (lo que se espera) y todavía no puedo acceder al método protegido test() (este también es el comportamiento esperado). Espero que el mismo comportamiento cuando se utiliza un código de ejemplo en lugar de C.

que explica una vez más:

class Foo { 
    protected function __construct() { 
     echo('Constructing ' . get_called_class()); 
    } 

    protected function test() { 
     echo('Hello world ' . __METHOD__); 
    } 
} 

class A extends Foo { 
    public function __construct() { 
     parent::__construct(); 
    } 

    public function testB() { 
     // Both of these lines work 
     $b = new B(); 
     $b->test(); 
    } 
} 

class B extends Foo { 
    protected function test() { 
     echo('Hello world Again ' . __METHOD__); 
    } 
} 

class C { 
    public function __construct() { 
    } 

    public function testB() { 
     // Both of these lines cause fatal errors 
     $b = new B(); 
     $b->test(); 
    } 
} 

$a = new A(); 
$a->testB(); 

$c = new C(); 
$c->testB(); 

que probablemente no estoy viendo algo, pero no puedo encontrar lo. ¿Alguien podría explicarme el comportamiento?

+0

Muy extraño comportamiento de hecho. – Sherlock

+0

¿Desea una explicación del fundamento o de la implementación detrás de este comportamiento? Dado que esto es PHP, hay una alta probabilidad de que * no * no tenga razón de ser. – Jon

+0

Si hay un razonamiento, me gustaría saber de qué se trata. – Arjan

Respuesta

6

Puede acceder a esos métodos porque hay una declaración de ellos como protegida en Foo, que es su padre y que le da permiso para acceder a él. Si elimina la declaración del padre y declara el método protegido en B, obtendrá un error fatal.

Esto se presenta como un fallo en PHP https://bugs.php.net/bug.php?id=50892

+0

No se puede llamar 'new B()' de 'A' si' B' anula '__construct' incluso si' Foo' lo declara. –

+2

Gracias por indicarme el enlace bugs.php.net. Busqué allí pero no pude encontrar el informe de error. – Arjan

1

No hay razón de esto, se ha informado hace 2 años: https://bugs.php.net/bug.php?id=52120

+0

Gracias por el enlace.Creo que es más extraño que puedas invocar métodos protegidos heredados que la imposibilidad de invocar constructores heredados (que es el comportamiento esperado, imo) – Arjan

Cuestiones relacionadas