22

PHP 5.4.5, here. I'm trying to invoke an object which is stored as a member of some other object. Like this (very roughly)

class A {
    function __invoke () { ... }
}

class B {
    private a = new A();
 ...
    $this->a();  <-- runtime error here
}

This produces a runtime error, of course, because there's no method called a. But if I write the call like this:

($this->a)();

then I get a syntax error.

Of course, I can write

$this->a->__invoke();

but that seems intolerably ugly, and rather undermines the point of functors. I was just wondering if there is a better (or official) way.

Prisoner
  • 27,391
  • 11
  • 73
  • 102
Jules May
  • 753
  • 2
  • 10
  • 18

3 Answers3

28

There's three ways:

Directly calling __invoke, which you already mentioned:

$this->a->__invoke();

By assigning to a variable:

$a = $this->a;
$a();

By using call_user_func:

call_user_func($this->a);

The last one is probably what you are looking for. It has the benefit that it works with any callable.

igorw
  • 27,759
  • 5
  • 78
  • 90
  • 1
    Thanks Igor. Of the three, the assignment to the variable seems like the most clear, but none of them are very nice. Does anybody understand why the 'obvious' syntax $this->a() can't find the __invoke method of the member - why is member access fundamentally different to naked variable syntax?? – Jules May Sep 26 '12 at 18:47
  • 2
    Because it's ambiguous. `$this->a()` could either be the method `a` or the member `$a`. In PHP those two are separated quite strongly (unlike JS, for example). – igorw Sep 27 '12 at 00:44
13

FYI in PHP 7+ parenthesis around a callback inside an object works now:

class foo {                                                                     
    public function __construct() {                                             
        $this -> bar = function() {                                             
            echo "bar!" . PHP_EOL;                                              
        };                                                                      
    }                                                                           

    public function __invoke() {                                                
        echo "invoke!" . PHP_EOL;                                               
    }                                                                           
}                                                                               

(new foo)();                                                                    

$f = new foo;                                                                   
($f -> bar)(); 

Result:

invoke!
bar!
drmad
  • 530
  • 5
  • 16
5

I know this is a late answer, but use a combination of __call() in the parent and __invoke() in the subclass:

class A {
  function __invoke ($msg) {
    print $msg;
  }
}

class B {
    private $a;

    public function __construct() { $this->a = new A(); }

    function __call($name, $args)
    {
      if (property_exists($this, $name))
      {
        $prop = $this->$name;
        if (is_callable($prop))
        {
          return call_user_func_array($prop, $args);
        }
      }
    }
}

Then you should be able to achieve the syntactic sugar you are looking for:

$b = new B();
$b->a("Hello World\n");
Kris Oye
  • 1,158
  • 14
  • 27