I have been doing some tests (to replace old code) with the __invoke magic method and I'm not sure this is a bug or not:
Lets suppose we have a class:
class Calc {
function __invoke($a,$b){
return $a*$b;
}
}
The following is possible and works without any problem:
$c = new Calc;
$k = $c;
echo $k(4,5); //outputs 20
However if I want to have another class to store an instance of that object, this doesn't work:
class Test {
public $k;
function __construct() {
$c = new Calc;
$this->k = $c; //Just to show a similar situation than before
// $this-k = new Calc; produces the same error.
}
}
The error occurs when we try to call it like:
$t = new Test;
echo $t->k(4,5); //Error: Call to undefined method Test::k()
I know that a "solution" could be to have a function inside the class Test (named k) to "forward" the call using call_user_func_array but that is not elegant.
I need to keep that instance inside a common class (for design purposes) and be able to call it as function from other classes... any suggestion?
Update:
I found something interesting (at least for my purposes):
If we assign the "class variable" into a local variable it works:
$t = new Test;
$m = $t->k;
echo $m(4,5);
PHP thinks you want to call a method k on instance $t when you do:
$t->k(4, 5)
which is perfectly reasonable. You can use an intermediate variable to call the object:
$b = $t->k;
$b(4, 5);
See also bug #50029, which describes your issue.
When you do $test->k()
, PHP thinks you are calling a method on the $test
instance. Since there is no method named k()
, PHP throws an exception. What you are trying to do is make PHP return the public property k
and invoke that, but to do so you have to assign k
to a variable first. It's a matter of dereferencing.
You could add the magic __call
method to your Test
class to check if there is a property with the called method name and invoke that instead though:
public function __call($method, $args) {
if(property_exists($this, $method)) {
$prop = $this->$method;
return $prop();
}
}
I leave adding the arguments to the invocation to you.
You might also want to check if the property is_callable
.
But anyway, then you can do
$test->k();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With