PHP __call vs method_exists

2019-01-26 05:10发布

问题:

The Project I'm working on contains something like a wrapper for call_user_func(_array) which does some checks before execution. One of those checks is method_exists (In Case the supplied first argument is an instance of a class and the second is a method name) The other is_callable. The function will throw an exception if one of those checks fails.

My Code contains an array with function names (setFoo, setBar, etc.) and the php magic function for overloading (__call) which handles setting, replacing and deletion of certain variables (better certain array elements).

The Problem: method_exists will return false if the function is not defined.

Do I have any chance to get a true if the __call function does proper handling of the request?

回答1:

__call handles calls to methods that don't exist. method_exists is an introspection method that checks the existence of a method.

How can __call be determined to handle a method? I think you have to throw an exception manually in __call if doesn't handle your request and catch the exception in the code that would otherwise use method_exists. BadMethodCallException exists for this purpose.



回答2:

Have a look at is_callable().

But no, if the __call() method only handles some names, then you would need some other way of checking if the call will succeed.

Might I suggest a interface with the method canCall($function), or something? Then check if the class implements the interface. If it doesn't, just use is_callable().



回答3:

method_exists tries two things:

  • Searches for the method name in the class's function table. Those are the function foo() {} type methods.
  • Checks if the class (the C code) has a (C code) get_method() function and if it has invoke it to let the class implementation decide.

You'd need the latter. But this get_method()is not "extended" to the php script code, i.e. there is no way to let get_method() call some user defined php script code (And what would this php code return?).

So the answer to my best knowledge is: No, it's not possible (yet?).

The implementation of ZEND_FUNCTION(method_exists) can be found in zend/zend_builtin_functions.c and is I think fairly readable even if you don't know C but PHP.



回答4:

I'd be tempted to maybe use method_exists in your __call function and throw an Exception should this fail and wrap everything in a try catch block instead of using the is_callable function.



回答5:

If you are really sure that _call always has a fall-back, you can do:

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