我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

php编程领域里,有两个特殊的函数调用方式,分别是:call_user_func()call_user_func_array()。可以用于使用比较特殊的统一的方式,执行用户的自定义函数。使用场景可以是:用户要调用的函数(方法)名并不明确的,或者需要经常变化的场景下。

苏南大叔:php教程,如何理解call_user_func和call_user_func_array? - call_user_func
php教程,如何理解call_user_func和call_user_func_array?(图3-1)

苏南大叔的“程序如此灵动”技术博客,记录苏南大叔的编程经验文章。本文测试环境:win10nginx@1.15.11php@8.2.10-nts

函数原型概述

根据php官方文档描述,

call_user_func()函数原型如下:

call_user_func(callable $callback, mixed ...$args): mixed

call_user_func_array()函数原型如下:

call_user_func_array(callable $callback, array $args): mixed

call_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里面增加了新的特性,可以在函数调用的时候,指定参数的名字。参考文章:

所以,在php8php8之前的版本中,下面的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.net

php8输出如下:

8.2.11
hi,苏南大叔,newsn.net
hi,newsn.net,苏南大叔

可见:在php8中,call_user_func_array()的第二个参数arraykey,作为参数名被解析了出来。

苏南大叔:php教程,如何理解call_user_func和call_user_func_array? - call_user_array
php教程,如何理解call_user_func和call_user_func_array?(图3-2)

处理参数引用

在用户定义某个php函数的时候,有些比较特殊的情况,使用&来表示参数的引用。以求获得执行函数后就改变外部引用的效果。例如:

$s = "苏南大叔";
$n = "newsn.net";
function hi(&$s,&$n){
    $s .= "!";
    $n = "https://".$n;
}
hi($s,$n);
echo $s,$n,PHP_EOL;

输出:

苏南大叔! https://newsn.net

苏南大叔:php教程,如何理解call_user_func和call_user_func_array? - 处理引用变量的方式
php教程,如何理解call_user_func和call_user_func_array?(图3-3)

对于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"
}

相关文章

结束语

所以,对于call_user_func()call_user_func_array()来说,最大的区别就是如何传递目标函数(方法)的参数,并且call_user_func_array()可以处理参数引用的情况。

更多苏南大叔的php经验文章,请点击:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   php