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): 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
里面增加了新的特性,可以在函数调用的时候,指定参数的名字。参考文章:
所以,在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.net
php8
输出如下:
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
经验文章,请点击:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。