在 PHP 中通过引用传递函数


Pass a function by reference in PHP

可以通过引用传递函数吗?

像这样:

function call($func){
    $func();
}
function test(){
    echo "hello world!";
}
call(test);

我知道你可以做'test',但我真的不想这样,因为我需要通过引用传递函数。

这是通过匿名函数执行此操作的唯一方法吗?

澄清:如果您从C++中回想一下,您可以通过指针传递函数:

void call(void (*func)(void)){
    func();
}

或者在 Python 中:

def call(func):
    func()

这就是我想要实现的目标。

对于它的价值,给这样的东西一个机会怎么样?(是的,我知道这是一个匿名函数,在帖子中提到过,但我对大量根本没有提到闭包/函数对象的回复感到不满,所以这主要是对遇到这篇文章的人的注释。

我不使用 PHP,但使用闭包似乎适用于 PHP 5.3(但不是 PHP 5.2(,如此处所示。我不确定有什么限制,如果有的话。(据我所知,关闭会吃掉你的孩子。你已经被警告了。

function doIt ($fn) {
  echo "doIt'n";
  return $fn();
}
function doMe () {
  echo "doMe'n";
}
// I am using a closure here.
// There may be a more clever way to "get the function-object" representing a given
// named function, but I do not know what it is. Again, I *don't use PHP* :-)
echo doIt(function () { doMe(); });

快乐编码。

call_user_func()的问题在于你传递的是所调用函数的返回值,而不是函数本身。

我以前也遇到过这个问题,这是我想出的解决方案。

function funcRef($func){
  return create_function('', "return call_user_func_array('{$func}', func_get_args());");
}
function foo($a, $b, $c){
    return sprintf("A:%s B:%s C:%s", $a, $b, $c);
}
$b = funcRef("foo");
echo $b("hello", "world", 123);
//=> A:hello B:world C:123

ideone.com 演示

不,函数不是 PHP 中的第一类值,它们不能通过名称文字传递(这是您所要求的(。即使是匿名函数或通过create_function创建的函数也由对象或字符串引用传递。

可以将函数的名称作为字符串传递,将对象方法的名称作为数组传递(object, string)或者将匿名函数作为对象传递。这些传递指针或引用都不是,它们只是传递函数的名称。所有这些方法都称为callback伪类型:http://php.net/callback

function func1(){
    echo 'echo1 ';
    return 'return1';
}
function func2($func){
    echo 'echo2 ' . $func();
}
func2('func1');

结果:

echo1 echo2 return1

在 PHP 5.4.4 中(尚未测试过较低版本或其他版本(,您可以完全按照您的建议进行操作。

以这个为例:

function test ($func) {
    $func('moo');
}
function aFunctionToPass ($str) {
    echo $str;
}
test('aFunctionToPass');

脚本将回显"moo",就像您直接调用"aFunctionToPass"一样。

这个

Javascript第一类函数的类似模式:

function add(first, second, callback){
    console.log(first+second);
    if (callback) callback();
}
function logDone(){
    console.log('done');
}
function logDoneAgain(){
    console.log('done Again');
}
add(2,3, logDone);
add(3,5, logDoneAgain);

可以在PHP中通过以下方式完成(在C9 IDE上使用5.5.9-1ubuntu测试(:

// first class function
$add = function($first, $second, $callback) {
  echo "'n'n". $first+$second . "'n'n";
  if ($callback) $callback();
};
function logDone(){
  echo "'n'n done 'n'n";
}
call_user_func_array($add, array(2, 3, logDone));
call_user_func_array($add, array(3, 6, function(){
  echo "'n'n done executing an anonymous function!";
}));

结果:5 完成 9 完成执行匿名函数!

参考: https://github.com/zenithtekla/unitycloud/commit/873659c46c10c1fe5312f5cde55490490191e168

可以通过在声明函数时将函数分配给局部变量来创建引用:

$test = function() {
    echo "hello world!";
};
function call($func){
    $func();
}
call($test);

你可以说

$fun = 'test'; 
call($fun); 

而不是call(test);,使用 call_user_func('test');

从 PHP 8.1 开始,您可以使用 First 类可调用对象:

call(test(...));

您甚至可以使用方法:

call($obj->test(...));

就这么简单。

似乎有点不清楚为什么要通过引用传递函数?通常,仅当引用的数据需要(可能(由函数修改时,才会通过引用传递内容。

由于 PHP 使用数组或字符串来引用函数,

因此您可以通过引用传递数组或字符串,这将允许修改函数引用。

例如,您可以执行以下操作

<?php
$mysort = function($a, b) { return ($a < $b) ? 1 : -1; };
adjust_sort_from_config($mysort); // modifies $mysort
do_something_with_data($mysort);

哪里

<?php
function load_my_configuration(&$fun)
{
  $sort_memory = new ...;
  ...
  $fun = [$sort_memory, "customSort"];
  // or simply
  $fun = function($a, b) { return (rand(1,10) < 4 ? 1 : -1; };
}

这是有效的,因为有三种方法可以通过变量引用 PHP 中的函数:

  • $name – 字符串 $name 包含全局命名空间中应调用的函数的名称
  • array($object, $name( – 指对象$object的字符串$name的方法。
  • array($class, $name( – 指类 $class 的静态函数字符串$name。

如果我没记错的话,这些构造所指向的方法和静态函数必须是公共的。鉴于足够新的PHP版本,"第一类可调用语法"应该可以改善此限制,但它似乎只是Closure::fromCallable()周围的一些语法糖。

匿名函数在后台的工作方式相同。您只是在任何地方都看不到这些函数的文字随机名称,但对匿名函数的引用也只是一个变量的值。