Let's assume we have code like:
<?php
class Worker {
public function __invoke() {
echo "invoked\n";
}
}
class Caller {
public $worker;
public function __construct($worker) {
$this->worker = $worker;
}
public function __call($name, $arguments) {
echo "called\n";
}
}
$c = new Caller(new Worker());
echo $c->worker();
?>
The result is called
. What to do to get invoked
?
This problem exists also with anonymous functions which work the same. You have a few ways to work around:
1) modify your __call to check is it's a method, if not, invoke the property:
if (property_exists($this, $name) && is_object($this->$name) && method_exists($this->$name, "__invoke")) {
call_user_func_array($this->name, $args);
}
2) call __invoke
directly: $c->worker->__invoke();
3) Save the property into a temporary variable:
$tempVar = $c->worker;
$tempVar();
4) (nearly the same as 3) (source: http://marc.info/?l=php-internals&m=136336319809565&w=4)
${'_'.!$_=$c->worker}();
5) Use call_user_func
or call_user_func_array
:
call_user_func($c->worker);
I experienced the same problem and it comes that (as you see) it's difficult to tell which object you mean.
The only way (that is "almost" clear) is to use an auxiliary variable
$temp = $c->worker;
$temp(); // should be now invoked
Update:
In case you don't want to implement the __call() Method on all your Callables I'd just extend the Callable like this:
<?php
class Worker {
public function __invoke() {
echo "invoked\n";
}
}
class InvokeCaller{
public function __call($name, $arguments) {
if(property_exists($this, $name) && is_object($this->{$name}))
$this->{$name}->__invoke($arguments);
else
echo "called\n";
}
}
class Caller extends InvokeCaller{
public $worker;
public function __construct($worker) {
$this->worker = $worker;
}
}
class AnotherCaller extends InvokeCaller{
public $anotherWorker;
public function __construct($worker) {
$this->anotherWorker = $worker;
}
}
$c = new Caller(new Worker());
$c2 = new AnotherCaller(new Worker());
echo $c->worker();
echo $c2->anotherWorker();
?>
Old
I came up with this one
<?php
class Worker {
public function __invoke() {
echo "invoked\n";
}
}
class Caller {
public $worker;
public function __construct($worker) {
$this->worker = $worker;
}
public function __call($name, $arguments) {
if(property_exists($this, $name) && is_object($this->{$name}))
$this->{$name}->__invoke($arguments);
else
echo "called\n";
}
}
$c = new Caller(new Worker());
echo $c->worker();
?>
We're just modifying our call.
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