How to ensure that we use __invoke by property, and not __call on the main object?

Suppose 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(); ?> 

Result called . What to do to get invoked ?

+7
source share
4 answers

This problem exists with anonymous functions that work the same way. You have several ways to get around:

1) modify your __call to check if it is a method, if not, call 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 to a temporary variable:

 $tempVar = $c->worker; $tempVar(); 

4) (almost 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); 
+4
source

I had the same problem, and it seems to me that (as you see) it is difficult to determine which object you have in mind.

The only way (that is, "almost clear") is to use an auxiliary variable

 $temp = $c->worker; $temp(); // should be now invoked 
+2
source

Update:

If you do not want to implement the __call () method in all of your Callables, I would simply extend Callable as follows:

 <?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

 <?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 just modify our call.

+2
source

If the transfer request is accepted, we get the syntax as:

 echo ($c->worker)(); //outputs "invoked" 
0
source

All Articles