php教程,如何理解call_user_func和call_user_func_array?
发布于 作者:苏南大叔 来源:程序如此灵动~
在php编程领域里,有两个特殊的函数调用方式,分别是:call_user_func()和call_user_func_array()。可以用于使用比较特殊的统一的方式,执行用户的自定义函数。使用场景可以是:用户要调用的函数(方法)名并不明确的,或者需要经常变化的场景下。

苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的编程经验文章。本文测试环境:win10,nginx@1.15.11,php@8.2.10-nts。
函数原型概述
根据php官方文档描述,
- https://www.php.net/manual/zh/function.call-user-func.php
- https://www.php.net/manual/zh/function.call-user-func-array.php
call_user_func()函数原型如下:
call_user_func(callable $callback, mixed ...$args): mixedcall_user_func_array()函数原型如下:
call_user_func_array(callable $callback, array $args): mixedcall_user_func()和call_user_func_array(),这两个函数使用上基本差不多,
- 把第一个参数作为回调函数(
callback)调用。 - 剩余的是该对该函数
callback(方法)传递的参数。前者是分开传递,后者是打包传递。
最常见的情况
这里举例最简单的使用情况,一般来说,看这里就足够了。
function hi($s,$n){
echo 'hi,',$s,',',$n,PHP_EOL;
}
call_user_func("hi","苏南大叔","newsn.net"); // hi,苏南大叔,newsn.net
call_user_func_array("hi",["苏南大叔","newsn.net"]); // hi,苏南大叔,newsn.net实际上,执行系统自带的函数也是可以的,所以函数里面的_user_的概念,并不是很准确。
echo strlen("苏南大叔"); // 12
echo call_user_func("strlen","苏南大叔"); // 12
echo call_user_func_array("strlen",["苏南大叔"]); // 12一个汉字的长度,返回值居然是3 !!!
php8视角下的call_user_func_array()
由于php8里面增加了新的特性,可以在函数调用的时候,指定参数的名字。参考文章:
所以,在php8及php8之前的版本中,下面的call_user_func_array()的调用结果是不一样的。测试代码如下:
function hi($s,$n){
echo 'hi,',$s,',',$n,PHP_EOL;
}
echo PHP_VERSION,PHP_EOL;
call_user_func_array("hi",["苏南大叔","newsn.net"]);
call_user_func_array("hi",["n"=>"苏南大叔","s"=>"newsn.net"]);php7输出如下:
7.4.3
hi,苏南大叔,newsn.net
hi,苏南大叔,newsn.netphp8输出如下:
8.2.11
hi,苏南大叔,newsn.net
hi,newsn.net,苏南大叔可见:在php8中,call_user_func_array()的第二个参数array的key,作为参数名被解析了出来。

处理参数引用
在用户定义某个php函数的时候,有些比较特殊的情况,使用&来表示参数的引用。以求获得执行函数后就改变外部引用的效果。例如:
$s = "苏南大叔";
$n = "newsn.net";
function hi(&$s,&$n){
$s .= "!";
$n = "https://".$n;
}
hi($s,$n);
echo $s,$n,PHP_EOL;输出:
苏南大叔! https://newsn.net
对于call_user_func()来说,正常传递参数的(不写&)话,。结果并没有正确处理这种情况,并且会直接给出警告信息:
call_user_func("hi",$s,$n);Warning: hi(): Argument #1 ($s) must be passed by reference, value given in如果试图在参数传递的地方,写上&符号的话,则会直接报错:
call_user_func("hi",&$s,&$n);Parse error: syntax error, unexpected token "&", expecting ")"但是,call_user_func_array()却可以正确处理这种情况,例如:
call_user_func_array("hi",[&$s,&$n]);
echo $s,$n,PHP_EOL;输出:
苏南大叔! https://newsn.net调用类静态方法
call_user_func()和call_user_func_array()大多数情况下,是处理普通的用户自定义函数的。但是如果这些函数成为了某个类的静态方法,也是可以使用的。例如:
class SN
{
public static function hi($s, $n)
{
echo 'hi,', $s, ',', $n, PHP_EOL;
}
}
call_user_func("SN::hi", "苏南大叔", "newsn.net");
call_user_func_array("SN::hi", ["sunan大叔", "newsn.net"]);
call_user_func(__NAMESPACE__."\SN::hi", "苏南大叔", "newsn.net");
call_user_func_array(__NAMESPACE__."\SN::hi", ["sunan大叔", "newsn.net"]);输出:
hi,苏南大叔,newsn.net
hi,sunan大叔,newsn.net
hi,苏南大叔,newsn.net
hi,sunan大叔,newsn.net调用类普通方法
类的静态方法,相当于普通函数,这个很好理解。那么,如果要调用类里面的非静态方法呢?那么就需要先把类实例化,然后callback使用一个数组进行传递。例如:
class SN
{
private $greeting = "hola";
public function hola($s, $n)
{
echo $this->greeting,',', $s, ',', $n, PHP_EOL;
}
}
$sn = new SN;
call_user_func([$sn,'hola'],"苏南大叔","newsn.net");
call_user_func_array([$sn,'hola'],["苏南大叔","newsn.net"]);输出:
hola,苏南大叔,newsn.net
hola,苏南大叔,newsn.net调用匿名函数
下面的调用是一些特殊的写法,但是能正常执行。
call_user_func(function (){
$args = func_get_args();
var_dump($args);
},"苏南大叔","newsn.net");
call_user_func_array(function (){
$args = func_get_args();
var_dump($args);
},["苏南大叔","newsn.net"]);输出:
array(2) {
[0]=>
string(12) "苏南大叔"
[1]=>
string(9) "newsn.net"
}
array(2) {
[0]=>
string(12) "苏南大叔"
[1]=>
string(9) "newsn.net"
}相关文章
- https://newsn.net/say/php-static-method.html
- https://newsn.net/say/php-debug-func.html
- https://newsn.net/say/php-reflect-class.html
结束语
所以,对于call_user_func()和call_user_func_array()来说,最大的区别就是如何传递目标函数(方法)的参数,并且call_user_func_array()可以处理参数引用的情况。
更多苏南大叔的php经验文章,请点击: