2012-10-12 7 views
8

Czasami potrzebuję wykonać metodę dziadkową (to znaczy obejść metodę nadrzędną), wiem, że to jest zapach kodu, ale czasami nie mogę zmienić innych klas (frameworków, bibliotek itp.).Jak wywołać metodę typu grandparent bez otrzymania błędu E_STRICT?

W PHP można to zrobić z coś jak:

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

Problem polega na tym, że jeśli masz błędy E_STRICT włączona dostaniesz błąd jak:

surowe normy: metody non-statyczne GrandParent :: grandParentMethod() nie powinien być wywoływany statycznie w ...

Znalazłem tylko jedno rozwiązanie w tym celu (bez usuwania E_STRICT), a to po prostu dodaje @ do s podnieść błąd.

Ale to naprawdę brzydkie, czy ktoś zna lepsze rozwiązanie?

Dzięki! PS: Nie mogę instancji nowego obiektu jak:

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

bo muszę zadzwonić do mojego sposobu dziadka w kontekście $ syna.

+0

Hej Enrique, wygląda na to, że odpowiedź Krinkla jest bardziej odpowiednia i klarowniejsza. Nie wymaga to również ustawiania publicznego dostępu do klasy dziadka, aby uzyskać do niej dostęp z poziomu wnuczki ... jeśli zgodzisz się, czy możesz zmienić zaakceptowaną odpowiedź na odpowiedź Krinkla? – a20

Odpowiedz

2

Można użyć ReflectionMethod->invoke()

Przykład:

<?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 

Uwaga: Wywołany metoda musi być publiczny.

+0

Myślę, że możemy użyć setAccessible dla metod niepublicznych. W każdym razie, gdzie jest to tutaj? w większości przypadków muszę używać dziadka w klasie mojego syna, a program Granparent musi zmieniać rzeczy na moim obiekcie $ this (son), a nie nowym. Dziwne jest to, że w tym przypadku PHP (5.3.13) nie pokazuje ostrzeżenia E_SRICT, gdy robię coś takiego: GrandParent :: method(); wewnątrz mojej klasy Son (a także przy założeniu poprawnego $ this). – Enrique

+1

Nie mogę powiedzieć, dlaczego wywołanie metody 'GrandParent :: method()' z klasy nie wymusza ostrzeżenia typu STRICT. $ to będzie obiekt, który wywoła metodę, $ syn w tym przypadku, więc zmiany na $ to będą dotyczyły $ syna tutaj. –

+2

Mam to samo pytanie, ale zgodnie z [ten oficjalny raport o błędach] (http://stackoverflow.com/questions/12850802/how-to-call-grandparent-method-without-getting--strict-error), jeśli kontekst jest właściwy (zakładam, że oznacza "z podklasy"), wywołanie 'GrandParent :: method()' ustawi '$ this' poprawnie i zezwoli na to wywołanie niestatyczne w sposób statyczny. –

0

Możesz użyć oddzielnej metody wewnętrznej (np. _doStuff w celu uzupełnienia doStuff) i wywołać ją bezpośrednio z wnuka, poprzez rodzica.

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

pokazuje

grandpa 
grandpa papa 
grandpa kiddo 
31

Możesz zadzwonić do dziadków bezpośrednio przez nazwę (bez call_user_func wiążący).

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'; 
    } 
} 

Base::getFoo połączenie może wyglądać statycznego rozmowy (z powodu składni okrężnicy ::), ale tak nie jest. Podobnie jak parent:: również nie jest statyczne. Wywołanie metody z łańcucha dziedziczenia w klasie poprawnie wiąże wartość $this, wywołaj ją jako zwykłą metodę, przestrzegaj reguł widoczności (np. Chronionych) i nie jest to naruszenie jakiegokolwiek rodzaju. Na początku może wydawać się to trochę dziwne, ale tak można to zrobić w PHP.

+3

To jest o wiele czystsze podejście niż zaakceptowana odpowiedź. Nie wiedziałem nawet, że możesz to zrobić w PHP do dzisiaj ... Dzięki @Krinkle – Brian

Powiązane problemy