Использование функции call_user_func_array в PHP
В PHP есть такая функция, которая называется call_user_func_array. Данная функции может использоваться для динамического вызова методов класса, как с параметрами так и без.
Особенно, данная функция может быть полезна при динамическом вызове обработчиков маршрутов в MVC коде.
Допустим у нас есть следующий класс контроллера статей ArticlesController. Код максимально упрощен для того, чтобы показать суть использования данной функции.
Функция call_user_func_array сама производит вызов метода контроллера и передает ему параметры, причем в каждый аргумент метода будет передано соответствующее значение параметра.
Вот такая полезная функции call_user_func_array есть в PHP.
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 0 ):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.
Copyright © 2010-2021 Русаков Михаил Юрьевич. Все права защищены.
call_user_func
(PHP 4, PHP 5, PHP 7, PHP 8)
call_user_func — Вызывает callback-функцию, заданную в первом параметре
Описание
Список параметров
Ноль или более параметров, передаваемые в callback-функцию.
Учтите, что параметры для call_user_func() не передаются по ссылке.
Пример #1 Пример использования call_user_func() и ссылки
Результат выполнения данного примера:
Возвращаемые значения
Возвращает значение, возвращённое callback-функцией.
Примеры
Пример #2 Пример использования call_user_func()
Результат выполнения данного примера:
class Foo <
static public function test () <
print «Привет, мир!\n» ;
>
>
Результат выполнения данного примера:
Пример #4 Вызов метода класса с помощью call_user_func()
class myclass <
static function say_hello ()
<
echo «Привет!\n» ;
>
>
$myobject = new myclass ();
Результат выполнения данного примера:
Пример #5 Использование лямбда-функции с call_user_func()
Результат выполнения данного примера:
Примечания
Смотрите также
User Contributed Notes 31 notes
I benchmarked the comparison in speed between variable functions, call_user_func, and eval. My results are below:
Variable functions took 0.125958204269 seconds.
call_user_func took 0.485446929932 seconds.
eval took 2.78526711464 seconds.
This was run on a Compaq Proliant server, 180MHz Pentium Pro 256MB RAM. Code is as follows:
function fa () < return 1 ; >
function fb () < return 1 ; >
function fc ()
$calla = ‘fa’ ;
$callb = ‘fb’ ;
$callc = ‘fc’ ;
if you simply want to dynamically call a method on an object it is not necessary to use call_user_function but instead you can do the following:
$obj = new ClassName ();
?>
I’ve used the above so I know it works.
@insta at citiesunlimited dot com & @Maresa
call_user_func() alleged slowness is quite over estimated when it comes to real use cases. we are talking about loosing fraction of a second every million calls, which by the way would take less than half a sec to execute in the worst case.
I don’t know of many processes that would actually suffer from this kind of overhead.
You don’t need to use this function to call a variable class function. Instead you can do the following:
The example works in PHP 5 from within the class. It is the <> that do the trick.
>phil at gettcomm dot com
>22-May-2002 04:51
>if you need to get a reference back from a method, you can work around
>call_user_func()’s shortcomings like this:
>
Naaa! Having back a reference is a real problem, but it can be solved by mean of eval(), instead of using call_user_func:
An entirely OO solution to add dynamicly methods to classes, I used in a project:
class ProductPart <
With this class, you can dynamicly add and remove classes by calling register or unregister. Register will store the object in an associative array by calling toString (as defined by ProductPlugin) and saving the method under the returned string in the array. (In this case the name of the method the class adds.)
When a method is called, which isn’t standard in the object, _call will lookup the called method in the array. If found, __call run the method of the plugin with the provided arguments. I restricted the user provided argument to 1, because I want to force the user to use associative arrays.
Because I chose an array to store my classes, removing a function is quite simple. However the unregister function isn’t optimal, I better pass a string instead of a plugin object. I didn’t test it yet on performance.
The ProductPlugin class:
?>
And at last some demonstration code:
call_user_func_array
(PHP 4 >= 4.0.4, PHP 5, PHP 7, PHP 8)
call_user_func_array — Вызывает callback-функцию с массивом параметров
Описание
Список параметров
Передаваемые в функцию параметры в виде индексированного массива.
Возвращаемые значения
Возвращает результат функции или false в случае возникновения ошибки.
Примеры
Пример #1 Пример использования функции call_user_func_array()
Результатом выполнения данного примера будет что-то подобное:
Пример #2 Пример использования call_user_func_array() c именем пространства имён
Результатом выполнения данного примера будет что-то подобное:
Пример #3 Использование лямбда-функции
Результат выполнения данного примера:
Пример #4 Передача значений по ссылке
Результат выполнения данного примера:
Примечания
Смотрите также
User Contributed Notes 38 notes
As of PHP 5.6 you can utilize argument unpacking as an alternative to call_user_func_array, and is often 3 to 4 times faster.
Just hope this note helps someone (I killed the whole day on issue).
I just pulled my hair out with an old installation of CakePHP because it was passing NULL instead of an empty array.
For anyone looking for the means to test for the first parameter before passing to this function, look at the is_callable (http://php.net/manual/en/function.is-callable.php) variable handler.
It appears that when PHP executes something like:
suddenly, inside foo, the second parameter is passed by reference!
And you can’t call this wrong, only another subtly of references.
Note it appears that ksort($a) will remove the reference as well as put the elements in key order so you (probably) get what you expect. (see below on the use of a foreach ($a as &v).)
$f = new foo_bar3 ( «abc» );
?>
Instead, use the direct name of the class as string or, better, the magic constant __CLASS__ in call_user_func_array(), like:
Then the parameters will be correctly redirected to the lowest base class.
Since PHP 5.6 you can use the spread operator (argument unpacking) instead of call_user_func_array().
$param_arr may be empty, though it can’t be null.
Note the code here is an example of usage. The actual hack is denoted by comments.
If someone knows a better alternative, by all means, i would love to see it.
call_user_func_array can pass parameters as reference:
Be aware the call_user_func_array always returns by value, as demonstrated here.
Here is a function you can use in place of call_user_func_array which returns a reference to the result of the function call.
call_user_func_array() is nifty for calling PHP functions which use variable argument length. For example:
There’s a possibility that call_user_func_array(), call_user_func(), and Exception::getTrace() will cause a trace entry to not have the ‘file’ or ‘line’ elements.
I came up with a better solution to the problem that I solve below with createObjArray that maintains parameter type:
?>
Would be good to add error checking, but it works.
Regarding the comments below about calling parent constructors:
PHP5 with E_STRICT no longer allows calls as below:
Note that call_user_func() will completely trash debug_backtrace().
?>
Note the 3 dots (array unpacking syntax).
PLS notice that «patripaq at hotmail dot com» ‘s code will be valid if B EXTENDS A.
class B extends A <
.
>
?>
there>>»What I wanted to do is create an object that can manage any number and any kind of parameters.»
BUT IT IS NOT A POINT AT ALL
If you need to call just function with parameters:
call_user_func_array(‘Foo’,$args);
If you need to call CLASS method (NOT object):
call_user_func_array(array(‘class’, ‘Foo’),$args);
If you need to call OBJECT method:
call_user_func_array(array(&$Object, ‘Foo’),$args);
If you need to call method of object of object:
call_user_func_array(array(&$Object->Object, ‘Foo’),$args);
If you need to call object method from within the very same object (NOT CLASS!):
call_user_func_array(array(&$this, ‘Foo’),args);
The call_user_func_array ITSELF can manage any number and any kind of parameters. It can handle ANY FUNCTION too as it is defined and that maybe partipaq wanted to manage.
For those of you that have to consider performance: it takes about 3 times as long to call the function this way than via a straight statement, so whenever it is feasible to avoid this method it’s a wise idea to do so.
Note that eval() is about 10 times slower than a straight statement to call a function with arguments, so this is definitely a better option than using eval() even if you only consider performance.
An implementation where parameters are submitted by their name.
This function calls class functions, class methods, functions and anonymous functions.
call_user_func_array
call_user_func_array — Вызывает пользовательскую функцию с массивом параметров
Описание
Вызывает пользовательскую функцию function, с параметрами из массива param_arr.
Список параметров
Передаваемые в функцию параметры, в качестве индексированного массива.
Возвращаемые значения
Возвращает результат функции или FALSE в случае ошибки.
Список изменений
| Версия | Описание |
|---|---|
| 5.3.0 | Изменилась интерпретация объектно-ориентированных ключевых слов, таких как parent и self. Ранее, их вызов с помощью синтаксиса двойного двоеточия вызывал предупреждение уровня E_STRICT, так как они расценивались как статические вызовы. |
Примеры
Пример #1 Использование call_user_func_array()
Результатом выполнения данного примера будет что-то подобное:
Пример #2 Пример использования call_user_func_array() и имени из пространства имен
Результатом выполнения данного примера будет что-то подобное:
Пример #3 Использование lambda-функции
Результат выполнения данного примера:
Примечания
Переменные-ссылки в param_arr передаются в функцию по ссылке, вне зависимости от того, ожидает ли функция передачу соответствующего параметра по ссылке или нет. Эта форма «динамической» передачи по ссылке не выводит замечания об устаревшем поведении, но тем не менее считается устаревшей, и, скорее всего, будет удалена в следующей версии PHP. Далее, это не влияет на встроенные функции, у которых учитывается сигнатура функции. Передача по значению параметра функции, при ожидаемой передачи по ссылке, вызовет предупреждение и заставит call_user_func() вернуть FALSE (за исключением если переданное значение имеет количество ссылок (reference count) равное 1).
why should one prefer call_user_func_array over regular calling of function?
As I can see both regular one and call_user_func_array method both outputs same, then why should one prefer it?
In which scenario regular calling method will fail but call_user_func_array will not?
Can I get any such example?
6 Answers 6
You have an array with the arguments for your function which is of indeterminate length.
The alternative would be:
Which is not a solution.
The use case for this may be rare, but when you come across it you need it.
If you don’t know beforehand how many arguments you’re going to pass to your function, it would be advisable to use call_user_func_array() ; the only alternative is a switch statement or a bunch of conditions to accomplish a predefined subset of possibilities.
Note that using call_user_func_* functions can’t be used to call private or protected methods.
The alternative to all of this is to make your functions accept an array as its only argument:
However, this eliminates the possibility to type-hint each argument in your function declaration and is generally considered a code smell.
You should prefer calling the function as you’d do regularly. Use call_user_func_array with dynamic arguments. For example:
call_user_func_array performs «uncurrying», which is the opposite of «currying».
If we want to accept multiple arguments, PHP lets us do that with 3 different APIs. The usual way is this:
Another way is called curried form:
The advantage is that all curried functions can be called in the same way: give them one argument.
If more arguments are required, more curried functions are returned, which ‘remember’ the previous arguments. This allows us to pass in some arguments now and the rest later.
There are some problems with this:
We can fix all of these issues by using a conversion function (disclaimer: that’s my blog). This lets us write and call our functions in the usual way, but gives them the same ‘memory’ ability as if they were curried:
The third way is called uncurried and takes all of its arguments in one:
Just like with curried functions, uncurried functions can all be called with one argument, although this time it’s an array. We still face the same compatibility problems as curried functions: if we choose to use uncurried functions, we can’t rely on everyone else choosing the same. Hence we also need a conversion function for uncurrying. That’s what call_user_func_array does:
Interestingly, we can get rid of that extra function($args) wrapper (a process known as «eta-reduction») by currying call_user_func_array :
Unfortunately call_user_func_array isn’t as smart as curry ; it won’t automatically convert between the two. We can write our own uncurry function which has that ability:
These conversion functions show that PHP’s «usual» way of defining functions is actually redundant: if we replaced PHP’s «usual» functions with ‘smart’ curried or uncurried ones, lots of code would carry on working. If we did that, it’s better to curry everything and selectively uncurry as needed, since that’s easier than going the other way around.
Unfortunately, some things which expect a variable number of arguments using func_get_args would break, as well as functions with default argument values.
Interestingly, default values are just a special form of currying. We could mostly do without them if we put those arguments first instead of last, and provided a bunch of alternative definitions which curry in the defaults. For example:



