2012-10-12 13 views
8

A volte ho bisogno di eseguire il metodo grandparent (cioè bypassare il metodo genitore), so che questo è odore di codice, ma a volte non riesco a cambiare le altre classi (framework, librerie, ecc.).Come chiamare il metodo grandparent senza ottenere l'errore E_STRICT?

In PHP possiamo farlo con qualcosa di simile:

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

Il problema è che se si dispone di errori E_STRICT attivato si otterrà un errore del tipo:

norme severe: metodo non statico GrandParent :: grandParentMethod() non dovrebbe essere chiamato staticamente in ...

Ho trovato solo una soluzione per questo (senza rimuovere E_STRICT), ed è solo aggiungendo il @ a s aggiustare l'errore.

Ma questo è davvero brutto, qualcuno conosce una soluzione migliore?

Grazie! PS: Non riesco a un'istanza di un nuovo oggetto del tipo:

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

perché ho bisogno di chiamare il mio metodo nonni nel contesto di $ figlio.

+0

Hey Enrique, sembra che la risposta di Krinkle sia più adatta e più chiara. Inoltre, non richiede che tu imposti l'accesso pubblico alla classe nonna per accedervi dalla classe nipote ... se sei d'accordo, potresti cambiare risposta accettata alla risposta di Krinkle? – a20

risposta

2

È possibile utilizzare ReflectionMethod->invoke()

Esempio:

<?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: Il metodo richiamato deve essere pubblico.

+0

Suppongo che possiamo usare setAccessible per metodi non pubblici. Comunque, dov'è $ questo qui? nella maggior parte dei casi ho bisogno di usare nonni nella classe di mio figlio, e granparent deve cambiare le cose sul mio oggetto $ this (figlio) non nuovo. La cosa strana è che in questo caso PHP (5.3.13) non mostra l'avviso E_SRICT quando faccio qualcosa del tipo: GrandParent :: method(); all'interno della mia classe Son (e anche assumendo il corretto $ this). – Enrique

+1

Non posso dirti perché la chiamata di 'GrandParent :: method()' all'interno della classe non forza l'avvertimento STRICT. $ questo sarà l'oggetto che invoca il metodo, $ figlio in questo caso, quindi le modifiche a $ verranno applicate a $ figlio qui. –

+2

Ho avuto la stessa domanda, ma secondo [questo bug report ufficiale] (http://stackoverflow.com/questions/12850802/how-to-call-grandparent-method-without-getting-e-strict-error), se il contesto è corretto (presumo che significhi 'da una sottoclasse'), la chiamata 'GrandParent :: method()' imposterà '$ this' correttamente e consentirà questa chiamata non statica in modo statico. –

0

È possibile utilizzare un metodo interno separato (ad esempio _doStuff per integrare doStuff) e chiamarlo direttamente dal nipotino, tramite il genitore.

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

mostra

grandpa 
grandpa papa 
grandpa kiddo 
31

è possibile chiamare i nonni direttamente per nome (senza alcun call_user_func vincolante).

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 chiamata Base::getFoo può apparire come una chiamata statica (a causa della sintassi colon ::), ma non lo è. Proprio come parent:: non è statico, neanche. La chiamata di un metodo dalla catena di ereditarietà all'interno di una classe associerà correttamente il valore $this, invocandolo come metodo normale, rispettando le regole di visibilità (ad esempio protetto) e non è una violazione di alcun tipo. All'inizio può sembrare un po 'imbarazzante, ma questo è il modo di farlo in PHP.

+3

Questo è un approccio molto più pulito rispetto alla risposta accettata. Non sapevo nemmeno che potresti farlo in PHP fino ad oggi ... Grazie a @Krinkle – Brian

Problemi correlati