-1

I am trying to setup a PHP method that gets passed an object and its method name, then gets calls that method of the object. I am trying to limit the usage of strings in my code, so I would like to do it using a custom enum. When I run this example though, this is the output I receive:

getTest

WARNING call_user_func() expects parameter 1 to be a valid callback, second array member is not a valid method on line number 43

echo call_user_func(array($object, $method));

Although it seems to print out the correct method, it says the method being passed isn't a valid method. I'm confused because I followed the tutorial on PHP.net

http://php.net/manual/en/function.call-user-func.php

What is the proper way to use call_user_func on a class's method? Please let me what I am missing/doing wrong?

abstract class MyEnum
{
    final public function __construct($value)
    {
        $c = new ReflectionClass($this);
        if(!in_array($value, $c->getConstants())) {
            throw IllegalArgumentException();
        }
        $this->value = $value;
    }

    final public function __toString()
    {
        return $this->value;
    }
}

class one {
    private $test = 1;
    
    public function getTest() {
        return $this->test;
    }
}

class two {
    private $quiz = 2;
    
    public function getQuiz() {
        return $this->quiz;
    }
}

class Number extends MyEnum {
    const ONE = "getTest";
    const TWO = "getQuiz";
}

function testCallback($object, $method) {
    echo $method;
    echo call_user_func(array($object, $method));
}

$temp1 = new one();
$temp2 = new two();

testCallback($temp1, new Number(Number::ONE));
Community
  • 1
  • 1
styro103
  • 39
  • 2
  • 7
  • 1
    `testCallback($temp1, Number::ONE);` – shudder Aug 12 '17 at 02:49
  • why not just do this `$object->$method()` if you have no arguments. The only time to use `call_user_*` is when you have a variable number of arguments and even then you'd use `call_user_func_array` – ArtisticPhoenix Aug 12 '17 at 02:56
  • Yup, that was it. Thank you shudder. – styro103 Aug 12 '17 at 02:57
  • ArtisticPhoenix because the project I want to use this concept for will have arguments. This was just something I put together to test how to get it working. – styro103 Aug 12 '17 at 03:00

1 Answers1

1

This is how I would do it, as I said in the comments you can call it directly without invoking an additional function call

function testCallback($object, $method) {
   echo $method;
   if( !method_exists( $object, $method) ) throw new Exception( "Method does not exist ".$object::class.'::'.$method);
   echo $object->$method();
}

The only time to use call_user_func* is when you have arguments ( even then you could use reflection ) Such as this.

function testCallback($object, $method, array $args = []) {
   echo $method;
   if( !method_exists( $object, $method) ) throw new Exception( "Method does not exist ".$object::class.'::'.$method);
   echo call_user_func_array( [$object,$method], $args);
}

Or with reflection ( probably tiny bit slower )

function testCallback($object, $method, array $args = []) {
   echo $method;
   if( !method_exists( $object, $method) ) throw new Exception( "Method does not exist ".$object::class.'::'.$method);
   echo (new ReflectionMethod( $object, $method))->invokeArgs( $object, $args );
}
ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38