Именованные функции, анонимные функции, статические методы, методы экземпляров и объекты с методом «__invoke» вместе называются «вызываемыми». Если у меня есть вызываемый объект, то должен быть в состоянии вызвать его, поставив после него круглые скобки "()" (я предполагаю, что аргументы не нужны) Это работает, когда наш вызываемый объект хранится в переменной, например:
$f(); // Call $f
Однако, что если я сохраню вызываемый объект в свойстве объекта?
$obj = new stdClass;
$obj->my_func = function() {};
$obj->my_func(); // Error: stdClass does not have a "my_func" method
Проблема в том, что синтаксический анализатор PHP запутывается, потому что код неоднозначен, это может означать вызов вызываемого свойства или вызов метода. PHP всегда рассматривает этот вид кода как вызов метода, поэтому мы не можем вызывать вызываемые свойства таким образом. Вот почему нам нужен call_user_func:
call_user_func($obj->my_func); // Calls $obj->my_func
В других случаях PHP не понимает нормальный синтаксис скобок; например, PHP в настоящее время (5.5) не знает, как вызвать возвращаемое значение другого вызываемого объекта:
get_a_callable()(); // Parse error, unexpected "("
call_user_func(get_a_callable()); // Calls the return value of get_a_callable
В настоящее время также невозможно напрямую вызывать определение функции, что полезно для обхода отсутствия в PHP операторов «let», например:
function($x) { echo $x . $x; }('hello'); // Parse error, unexpected "("
call_user_func(function($x) { echo $x . $x; }, 'hello'); // Calls the function
В некоторых случаях полезно иметь вызовы функций / reified / в качестве функции call_user_func. Например, при использовании функций высшего порядка, таких как array_map:
$funcs = [function() { return 'hello'; },
function() { return 'world'; }];
array_map('call_user_func', $funcs); // ['hello', 'world']
Это также полезно, когда мы не знаем, сколько параметров потребуется, т.е. мы не можем заменить нашу собственную "функцию ($ f, $ x, $ y, ...) {return $ f ($ x, $ y, ...);}".
Одно особенно приятное определение - это частичное приложение, которое занимает всего несколько строк благодаря call_user_func и call_user_func_array:
function partial() {
$args1 = func_get_args(); // $f, $a, $b, $c, ...
return function() use ($args1) {
// Returns $f($a, $b, $c, ..., $d, $e, $f, ...)
$args2 = func_get_args(); // $d, $e, $f, ...
return call_user_func_array('call_user_func',
array_merge($args1, $args2));
};
}