2

Iam working on sample codes in php, I read the variable functions (which is kind of similar to function pointers in C) and started to write below code. Take a look at this

 class fruit{
     public $run;
 }

 function ano1(){
    // some statements
 }

 $x = 'ano1'; // variable function
 $x(); // works

 $f = new fruit;
 $f->run = 'ano1'; // lets store function to $run property
 $f->run(); // call to undefined method why?

Reason I think because it needs $this reference to be passed implicitly to ano1() which is not a member function? So using $this is not valid inside ano1() they simply did not implement it yet? But Iam a c++ background which is quite possible in c++:

class fruit{ 
   public : void (*run) ();
};

void ano1(){ cout << "im running" << endl; }

int main(){
  fruit f;
  f.run = ano1;
  f.run(); // works as long as you dont use this
}

Or is there a workaround in php as well? (Without closures and anonymous functions). Thank you

user3205479
  • 1,225
  • 1
  • 13
  • 35
  • Workaround requires the magic `__set()` and `__get()` methods : http://stackoverflow.com/questions/4713680/php-get-and-set-magic-methods ... but only with class members - PHP doesn't really do method overloading as such, see : http://stackoverflow.com/questions/4697705/php-function-overloading and http://www.php.net/manual/en/language.oop5.overloading.php – CD001 Sep 07 '15 at 14:51

3 Answers3

2

It works entirely differently than function pointers in C.

The particular reason for the error message you're seeing is that PHP cannot tell the difference between $fruit->run() and $fruit->run(); that is, the difference between calling the method run of $fruit, and calling whatever function name $fruit->run evaluates to. And it errs on the wrong side of what you expect. You can disambiguate with call_user_func($fruit->run).

PHP doesn't have anything like "function pointers". Functions are second class citizens in PHP. $x merely holds a string, and PHP's way of supporting passing functions around is to pass them by name. When attempting to "call a string", PHP will instead check if there's a function of that name, and call it instead.

So what you're doing is you're merely assigning a string to an object property, but PHP's syntax is too ambiguous to allow you to call it from there. It is not possible at all (with any sort of sane code) to graft a function onto an object after the fact. All object methods must be defined in the class of the object instance.

deceze
  • 471,072
  • 76
  • 664
  • 811
1

It's because doing $f->run() says 'call the run method of the $f object'.

Instead, you could do:

$str = $f->run;
$str();

which invokes the string as a function call.
Or

 $f = new fruit;
 $f->run = 'ano1';
 call_user_func($f->run)

which then simply invokes the property run as a method

A way that you could... sort of automate that is by using magic method __call like so:

class Fruit {

    public $run;

    public function __call($methodName,$argsArray){

        if (property_exists($this,$methodName)
                &&is_callable($this->$methodName)){
            return call_user_func_array($this->$methodName,$argsArray);
        } else {
            throw new \Exception("Method {$methodName} does not exist");
        }

    }
}

Then, you would do:

$fruit = new Fruit();
$fruit->run = 'ano1';
$fruit->run();

Then run is not defined in the class Fruit, so it passes the method name (run) to __call with any arguments you passed to run. Then if Fruit has a property named $methodName (in this case 'run'), and the property can be called as a function, then use call_user_func_array to invoke it as a function.

Reed
  • 13,861
  • 6
  • 61
  • 102
-1

Use the below code

$f->{$f->run}();

Since your was treating a run() method on a object of class fruit

user3535945
  • 243
  • 1
  • 10