5 minutes to read, 13.8K views since 2019.10.10 Читать на русском

How to invoke method on class with dynamicall generated name via reflection

Invoking without reflection

Lets say you have some object and want to call some method of it, fo example:

$controller->indexAction();

Thats ok, what if method name is not known in the moment you wrote your script and you need to get it from the variable, for example $method. Thats ok too:

$method = 'indexAction';
$object->{$method}();

but if the method not exists on object it would raise Fatal error and stop executing the script. You say that you can use function method_exists to check if the method on object exists, and you're right:

$method = 'indexAction';
if (method_exists($object,$method)) {
  $object->{$method}();
} else {
  echo "Method not exists";
}

what if you want to pass some parameters to the called method? if the number of parameters and their values are const then you can easily pass it to the invoke method declaration:

$object->{$method}($some,$param);

You even can pass dynamically created array to function call when you don't know how many parameters would you have and thei values by using call_user_func_array:

$params = [];

$params[] = 1;
$params[] = 'second param value';

call_user_func_array([$object,$method]), $params); // this would invoke $method on $object with two parameters

How to handle errors which can occur in case when number of parameters is wrong or some parameters are lacked? Or how to properly call static method of the object which is in namespace ?

call_user_func_array(__NAMESPACE__ .'\Controller::aliasAction',['about']);

This would do the trick, but this part of code looks terrible, am i right? In such cases its better to use Reflection Api to invoke methods on the objects. Lets have a look how to make such things done:

Invoke method of the class via reflection

At first you need to get the ReflectionMethod object which refers to class and method you need. It can be done in two ways:

  • by creating the instance of ReflectionMethod:

    $method = new ReflectionMethod('ClassName','MethodName');
    • by getting it via method getMethod with parameter - name of the method on the ReflectionClass obejct:
    $class = new ReflectionClass('ClassName');
    $method = $class->getMethod('MethodName');

Lets have a look at complex example calling a method with parameters done by features of ReflectionMethod clas:


 $controller = new IndexController(); // imagine its a controller from framework with mvc architecture
 $method = 'indexAction'; // you need to call indexAction on it

 $params = ['en','about'];

 try {
   $reflectionMethod = new ReflectionMethod($controller,$method); // this would throw an exception in case method is not exists on object
   $reflectionMethod->invokeArgs($controller,$params); // throws exception if parameters are wrong

 } catch (/ReflectionException $e) {
   echo 'Error calling method '.$method.' on IndexController';
 }

the above method allows you to invoke any method of the object in such way: static or usual, with parameters or without.

Invoking a private method of the object

Reflection api allows you to invoke even private methods of the objects. Suggest you have a class:

 class IndexController {

   private function disabledAction(){
     echo 'private action result';
   }

   // ... rest of code ...

 }

Its not allowed to invoke private method by default as in example above:

 $controller = new IndexController();
 $reflectionMethod = (new ReflectionClass($controller))->getMethod($method);  // you can also get ReflectionMethod from the ReflectionClass instance
 $reflectionMethod->invoke($controller); // invoke without arguments on the object $controller

would result in exception. Instead you should setAccesible your method before invoking it:

 $controller = new IndexController();
 $reflectionMethod = (new ReflectionClass($controller))->getMethod($method); 
 $reflectionMethod->setAccessible(true); // this makes method possible to invoke
 $reflectionMethod->invoke($controller);

After that ReflectionMethod would behave as simple method.

Pros and Cons

As for me its much more elegant code than using a call_user_func_array function. Of course, the method we chose to invoke a method depends on what we need to achieve: if wee need to use as much as low resources then its better to use functional style.

On the contrary, if we need more elegant code, more readable and written in object orientated style - its better to use Reflection Api. Reflection api throws exception and you don't need to handle error numbers which functional method returns in case of failed operation and so on. Moreover, reflection allows you to invoke private and protected methods which is not reachable by another methods.

Read next article Using getProperties to get the list of declared properties in course Reflection in PHP