2012-10-12 172 views
8

A veces tengo que ejecutar el método de abuelos (es decir, eludir el método principal), sé que esto es código malicioso, pero a veces no puedo cambiar las otras clases (marcos, bibliotecas, etc.).Cómo llamar al método de abuelos sin obtener el error E_STRICT?

En PHP podemos hacerlo con algo como:

call_user_func(array(get_parent_class(get_parent_class($childObject)), 'grandParentMethod')); 

El problema es que si se tiene habilitada errores E_STRICT obtendrá un error como:

normas estrictas: método no estático Abuelos :: grandParentMethod() no debería ser llamado de forma estática en ...

he encontrado una sola solución para esto (sin quitar E_STRICT), y es sólo la adición de la @ a s Subir el error.

Pero eso es realmente feo, ¿alguien sabe una mejor solución?

Gracias! PS: No puedo crear una instancia de un nuevo objeto como:

$grandparent = get_parent_class(get_parent_class($son)); 
$gp= new $grandparent; 
$gp->grandParentMethod 

porque tengo que llamar a mi método de abuelos en el contexto de $ hijo.

+0

Hola Enrique, parece que la respuesta de Krinkle es más adecuada y clara. Tampoco requiere que establezca el acceso público en la clase de abuelo para acceder desde la clase de nieto ... si está de acuerdo, ¿podría cambiar la respuesta aceptada a la respuesta de Krinkle? – a20

Respuesta

2

Es posible utilizar ReflectionMethod->invoke()

Ejemplo:

<?php 
class Grandpa { 
    protected $age = 'very old'; 
    public function sayMyAge() { 
     return 'sayMyAge() in Grandpa should be very old. ' . 
        'My age is: ' . $this->age; 
    } 
} 

class Pa extends Grandpa { 
    protected $age = 'less old'; 
    public function sayMyAge() { 
     return 'sayMyAge() in Pa should be less old. ' . 
        'My age is: ' . $this->age; 
    } 
} 

class Son extends Pa { 
    protected $age = 'younger'; 
    public function sayMyAge() { 
     return 'sayMyAge() in Son should be younger. ' . 
        'My age is: ' . $this->age; 
    } 
} 

$son = new Son(); 
$reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($son)), 
             'sayMyAge'); 
echo $reflectionMethod->invoke($son); 
// returns: 
// sayMyAge() in Grandpa should be very old. My age is: younger 

Nota: El método invocado debe ser pública.

+0

Supongo que podemos usar setAccessible para métodos no públicos. De todos modos, ¿dónde está $ aquí? en la mayoría de los casos necesito usar abuelos dentro de mi clase de hijo, y granparent debe cambiar las cosas en mi objeto $ this (son) y no en uno nuevo. Lo extraño es que en este caso PHP (5.3.13) no muestra la advertencia E_SRICT cuando hago algo como: GrandParent :: method(); dentro de mi clase Son (y también está asumiendo el $ correcto esto). – Enrique

+1

No puedo decirte por qué la llamada de 'GrandParent :: method()' dentro de la clase no fuerza la advertencia STRICT. $ este será el objeto que invoca el método, $ son en este caso, por lo que los cambios en $ esto se aplicarán a $ son aquí. –

+2

Tenía la misma pregunta, pero de acuerdo con [este informe oficial de error] (http://stackoverflow.com/questions/12850802/how-to-call-grandparent-method-without-getting-e-strict-error), si el contexto es correcto (supongo que eso significa 'de una subclase'), la llamada 'GrandParent :: method()' establecerá '$ this' correctamente y permitirá esta llamada no estática de una manera estática. –

0

Puede usar un método interno separado (por ejemplo, _doStuff para complementar doStuff) y llamarlo directamente desde el nieto, a través del padre.

// Base class that everything inherits 
class Grandpa { 
    protected function _doStuff() { 
     // grandpa's logic 
     echo 'grandpa '; 
    } 

    public function doStuff() { 
     $this->_doStuff(); 
    } 

} 

class Papa extends Grandpa { 
    public function doStuff() { 
     parent::doStuff(); 
     echo 'papa '; 
    } 
} 

class Kiddo extends Papa { 
    public function doStuff() { 
     // Calls _doStuff instead of doStuff 
     parent::_doStuff(); 
     echo 'kiddo'; 
    } 
} 

$person = new Grandpa(); 
$person->doStuff(); 
echo "\n"; 
$person = new Papa(); 
$person->doStuff(); 
echo "\n"; 
$person = new Kiddo(); 
$person->doStuff(); 

muestra

grandpa 
grandpa papa 
grandpa kiddo 
31

puede llamar al abuelo directamente por su nombre (sin call_user_func vinculante).

class Base { 
    protected function getFoo() { 
     return 'Base'; 
    } 
} 

class Child extends Base { 
    protected function getFoo() { 
     return parent::getFoo() . ' Child'; 
    } 
} 

class Grandchild extends Child { 
    protected function getFoo() { 
     return Base::getFoo() . ' Grandchild'; 
    } 
} 

La llamada Base::getFoo puede verse como una llamada estática (debido a la sintaxis de colon ::), sin embargo no lo es. Al igual que parent:: tampoco es estático. Llamar a un método de la cadena de herencia dentro de una clase vinculará correctamente el valor $this, lo invocará como un método normal, respetará las reglas de visibilidad (por ejemplo, protegido) y no constituye una violación de ningún tipo. Puede parecer un poco incómodo al principio, pero esta es la manera de hacerlo en PHP.

+3

Este es un enfoque mucho más limpio que la respuesta aceptada. Ni siquiera sabía que podrías hacer esto en PHP hasta hoy ... Gracias @Krinkle – Brian

Cuestiones relacionadas