PHP 5.4.5, здесь. Я пытаюсь вызвать объект, который хранится как член какого-либо другого объекта. Подобно этому (очень грубо)
class A { function __invoke () { ... } } class B { private a = new A(); ... $this->a(); <-- runtime error here }
Это, конечно, создает ошибку времени выполнения, потому что нет метода, называемого a. Но если я напишу так:
($this->a)();
то я получаю синтаксическую ошибку.
Конечно, я могу написать
$this->a->__invoke();
но это кажется невыносимо уродливым и скорее подрывает точку функторов. Мне просто интересно, есть ли лучший (или официальный) способ.
Существует три способа:
Непосредственно вызывая __invoke
, о котором вы уже говорили:
$this->a->__invoke();
Назначая переменной:
$a = $this->a; $a();
Используя call_user_func
:
call_user_func($this->a);
Последнее, вероятно, то, что вы ищете. Он имеет то преимущество, что он работает с любым вызываемым.
Я знаю, что это поздний ответ, но используйте комбинацию __call () в родительском и __invoke () в подклассе:
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); } } } }
Затем вы сможете достичь синтаксического сахара, который вы ищете:
$b = new B(); $b->a("Hello World\n");
FYI в PHP 7+ скобки вокруг обратного вызова внутри объекта работает сейчас:
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)();
Результат:
invoke! bar!