2010-06-10 13 views
13

Używam WordPressa jako CMS i chcę rozszerzyć jedną z jej klas bez konieczności dziedziczenia z innej klasy; czyli po prostu chce "dodać" więcej metod do tej klasy:Jak dodać metodę do istniejącej klasy w PHP?

class A { 

    function do_a() { 
     echo 'a'; 
    } 
} 

następnie:

function insert_this_function_into_class_A() { 
    echo 'b'; 
} 

(jakiś sposób wstawiania ten ostatni w klasie)

oraz:

A::insert_this_function_into_class_A(); # b 

Czy to możliwe nawet w wytrwałym PHP?

+0

"wytrwały PHP"? – Artefacto

+0

Czy edytowanie kodu źródłowego klasy stanowi opcję? –

+0

Tytuł był mylący; "rozszerzenie" odnosi się do dziedziczenia. Zmieniłem go, by lepiej odzwierciedlał twoje pytanie. – Artefacto

Odpowiedz

17

Jeśli tylko mieć dostęp do publicznych API klasy, można użyć Decorator:

class SomeClassDecorator 
{ 
    protected $_instance; 

    public function myMethod() { 
     return strtoupper($this->_instance->someMethod()); 
    } 

    public function __construct(SomeClass $instance) { 
     $this->_instance = $instance; 
    } 

    public function __call($method, $args) { 
     return call_user_func_array(array($this->_instance, $method), $args); 
    } 

    public function __get($key) { 
     return $this->_instance->$key; 
    } 

    public function __set($key, $val) { 
     return $this->_instance->$key = $val; 
    } 

    // can implement additional (magic) methods here ... 
} 

Następnie owinąć instancję SomeClass:

$decorator = new SomeClassDecorator(new SomeClass); 

$decorator->foo = 'bar';  // sets $foo in SomeClass instance 
echo $decorator->foo;   // returns 'bar' 
echo $decorator->someMethod(); // forwards call to SomeClass instance 
echo $decorator->myMethod(); // calls my custom methods in Decorator 

Jeśli chcesz mieć dostęp do API protected, musisz użyć dziedziczenia. Jeśli potrzebujesz dostępu do interfejsu API private, musisz zmodyfikować pliki klas. Chociaż podejście do dziedziczenia jest w porządku, modyfikowanie plików klas może spowodować problemy podczas aktualizacji (utracisz wszystkie wykonane poprawki). Ale oba są bardziej realne, niż przy użyciu runkita.

+1

Świetnie !. Działa to nie tylko w przypadku dodawania nowych metod do klasy, ale także nadpisywania ich, gdy opcja "rozszerzenia" nie jest opcją. – juanra

3

Możesz użyć do tego celu the runkit extension, ale zamiast tego powinieneś raczej rozważyć dziedziczenie.

Zobacz runkit_method_add.

+0

... podczas gdy runkit to tylko zabawka. – johannes

+1

@johannes Czasami jest to przydatne podczas debugowania. Ale to jest powód mojej rekomendacji, która jednak nie przeszkadza mi w odpowiadaniu na to pytanie. – Artefacto

+1

Zwróć uwagę na duże, czerwone "EKSPERYMENTALNE" ostrzeżenie na stronie podręcznika?Nie polecam do żadnego użytku produkcyjnego ... – selfawaresoup

2

Jeśli dana klasa stosuje magię __call, to jest to możliwe i dość łatwe. Jeśli chcesz się dowiedzieć, jak to działa, sugeruję przeczytanie Extending objects with new methods at runtime.

+0

Możliwe, ale dodaje ona wiele nieprzyjemnego kodu, który później może być trudny do utrzymania. Zwłaszcza "$ func = $ foo-> baz; $ func();" ma możliwą awarię napisaną na nim. :) – selfawaresoup

+0

Wiem, że to trudne do utrzymania, byłoby do diabła debugowanie i na pewno nie polecałbym go używać, ale to * jest * możliwe: p. – wimvds

-2

Nie można dynamicznie zmieniać klasy podczas uruchamiania w PHP.

Można to osiągnąć albo poprzez rozszerzenie klasy przy użyciu zwykłego dziedziczenia:

class Fancy extends NotSoFancy 
{ 
    public function whatMakesItFancy() //can also be private/protected of course 
    { 
     //  
    } 
} 

Albo można edytować WordPress pliki źródłowe.

Wolałbym dziedziczenie. O wiele łatwiej jest sobie z nimi radzić na dłuższą metę.

4

Zaktualizowany sposób na 2014 r., Który radzi sobie z zakresem.

public function __call($method, $arguments) { 
    return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments); 
} 

Np

class stdObject { 
    public function __call($method, $arguments) { 
     return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments); 
    } 
} 

$obj = new stdObject(); 
$obj->test = function() { 
    echo "<pre>" . print_r($this, true) . "</pre>"; 
}; 
$obj->test(); 
+1

Działa to naprawdę dobrze dla każdej nazwy klasy. W $ obj-> test możesz także wykonać $ this-> someClassMethod() i $ this-> privateVarName. Można także tworzyć funkcje wewnątrz funkcji składowych, które mają dostęp do metod i zmiennych klasy. –

Powiązane problemy