2009-10-01 12 views
14

Projekt, nad którym pracuję, zawiera coś w rodzaju wrappera dla funkcji call_user_func (_array), która wykonuje pewne sprawdzenia przed wykonaniem. Jedną z tych kontroli jest method_exists (W przypadku, gdy podany pierwszy argument jest instancją klasy, a drugi jest nazwą metody) Drugi to_przeprowadzalny. Funkcja rzuci wyjątek, jeśli jedna z tych kontroli nie powiedzie się.PHP __call vs method_exists

Mój kod zawiera tablicę z nazwami funkcji (setFoo, setBar itp.) Oraz funkcją php magic do przeciążania (__call), która obsługuje ustawianie, zastępowanie i usuwanie pewnych zmiennych (lepsze niektóre elementy tablicy).

Problem: method_exists zwróci false, jeśli funkcja nie jest zdefiniowana.

Czy mam szansę uzyskać wartość true, jeśli funkcja __call prawidłowo obsługuje żądanie?

+0

Wielkie pytanie, będę bawić się z tym. –

+0

Potrzebna jest kolejna "magiczna metoda" __canCall lub coś innego ... –

+1

is_callable() działa z instancjami klas. Nie widzę powodu, dla którego używasz method_exists() w ogóle. is_callable() robi wszystko method_exists() ma plus działa z __call(). – dave1010

Odpowiedz

4

method_exists próbuje dwie rzeczy:

  • wyszukuje nazwy metody w tabeli funkcji w klasie. Są to metody typu function foo() {}.
  • Sprawdza, czy klasa (kod C) ma funkcję (kod C) get_method() i czy wywołała ją, aby umożliwić decyzję o wykonaniu klasy.

Potrzebujesz tego drugiego. Ale ten get_method() nie jest "rozszerzony" na kod skryptu php, tzn. Nie ma sposobu, aby umożliwić get_method() wywołanie jakiegoś zdefiniowanego przez użytkownika kodu skryptu php (I co by ten kod php zwrócił?).

Więc odpowiedź na moją najlepszą wiedzę brzmi: Nie, to nie jest możliwe (jeszcze?).

Implementacja ZEND_FUNCTION(method_exists) znajduje się w zend/zend_builtin_functions.c i uważam, że jest całkiem czytelna, nawet jeśli nie znasz C, ale PHP.

5

Spójrz na is_callable().

Ale nie, jeśli metoda __call() obsługuje tylko niektóre nazwy, potrzebny jest inny sposób sprawdzenia, czy połączenie się powiedzie.

Czy mogę zaproponować interfejs z metodą canCall($function), czy coś w tym stylu? Następnie sprawdź, czy klasa implementuje interfejs. Jeśli nie, po prostu użyj is_callable().

+2

is_callable() automatycznie zwraca wartość true, jeśli zdefiniowano __call(), czyniąc parametr is_callable() niepodłączalnym (ponieważ nie zapewnia, że ​​funkcja __call() spełnia żądanie) –

8

__call obsługuje połączenia z metodami, które nie istnieją. method_exists to metoda introspekcji, która sprawdza istnienie metody.

Jak można ustawić __call do obsługi metody? Myślę, że musisz wyrzucić wyjątek ręcznie w __call, jeśli nie obsługuje twojego żądania i wychwycić wyjątek w kodzie, który w przeciwnym razie użyłby method_exists. BadMethodCallException istnieje w tym celu.

+1

Wygląda na to, że "__call" nie ma pojęcia "niepowodzenia", więc wygląda na to, że wyrzucenie 'NotImplementedException' (lub podobnego) w metodzie __call byłoby sposobem na zrobienie tego. –

1

byłbym skłonny do może używać method_exists w funkcji __call i throwException powinno zakończyć się niepowodzeniem i zawinąć wszystko w trycatch bloku zamiast używania funkcji is_callable.

1

Jeżeli jesteś pewien, że _call ma zawsze fall-back, można zrobić:

if (method_exists($this, $method_name) || method_exists($this, '__call')) { 
    // Call of the method 
}