【问题标题】:Pass a function by reference in PHP在 PHP 中通过引用传递函数
【发布时间】:2011-06-25 01:08:06
【问题描述】:

是否可以通过引用传递函数?

类似这样的:

function call($func){
    $func();
}

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

call(test);

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

只有通过匿名函数才能做到这一点吗?

澄清:如果你回忆一下 C++,你可以通过指针传递一个函数:

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

或者在 Python 中:

def call(func):
    func()

这就是我想要完成的。

【问题讨论】:

  • “需要通过引用传递函数”是什么意思?
  • 这个问题正在演变为争论,因为您没有阐明“通过引用传递”的含义(通过引用传递已经具有特定含义,我认为此处不适用)。投票结束。
  • 如果你回忆一下 C++,你可以传递一个函数的指针。这基本上就是我想要实现的目标。
  • 你刚才说:“你可以传值也可以传引用。”然后马上说我也做不到。
  • 引用传递在PHP中有不同的含义,它意味着如果你修改了一个引用传递的变量,原来的会被修改。从这个意义上说,它就像指针,但不一样。我说这不适用于函数,因为你不能修改函数。

标签: php


【解决方案1】:

为了它的价值,试试这样的东西怎么样? (是的,我知道它是一个匿名函数在帖子中提到,但我对没有提到闭包/函数的大量回复感到不满-完全没有对象,所以这主要是给在这篇文章中运行的人的注释。)

我不使用 PHP,但 using a closure 似乎在 PHP 5.3(但不是 PHP 5.2)中作为 demonstrated here 工作。 我不确定有什么限制,如果有的话。(据我所知,关闭会吃掉你的孩子。你已被警告过。)

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(); });

编码愉快。

【讨论】:

  • 这与 OP 自己已经提出的有什么不同?
  • 所以你将一个匿名函数传递给doIt。那是如何“通过引用传递doMe”的?抱歉,这个答案和其他答案一样无关紧要,主要是因为这个问题非常不清楚。
  • @ultimate 好吧,PHP 并不优雅
  • @macek 不,这正是 OP 所要求的。它在所需调用周围使用匿名函数闭包,因此接收此匿名函数作为参数的函数不需要知道它接收的是类方法还是全局函数。这是迄今为止最灵活的。
  • 为了澄清这一点,PHP 知道callables 的不同表示法:'globalFunctionName''ClassName::staticMethodName'array('ClassName', 'staticMethodName')array($object, 'methodName')。所有这些都与call_user_func()is_callable() 等一起工作 - documentation。尽管如此,它们在技术上并不是一个引用(符号 4 中的对象实例除外),而只是一个标识符。
【解决方案2】:

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 demo

【讨论】:

  • 这正是我所追求的。谢谢!
  • 与@user166390 的最高投票和接受答案相比,这实际上是我想要的,让我将不同的 C 风格“函数指针”传递给 PHP 函数,然后调用该函数带参数的指针。谢谢。
  • create_function() 自 PHP 7.2.0 起已弃用,自 PHP 8.0.0 起已删除。
【解决方案3】:

不,函数不是 PHP 中的一等值,它们不能通过它们的 name 字面量 传递(这是您所要求的)。甚至匿名函数或通过create_function 创建的函数也由对象或字符串引用传递。

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

【讨论】:

  • This link about Anonymous Functions 不同意这些功能不是一流的。 (授予“一流”是一个广泛的范围和火焰可以确保,但无论如何,这些对象可以根据示例直接调用 - 但我不使用 PHP,所以主要是钓鱼更好的解释。)那么如何将test 放入函数对象中?例如。可以$test2 = function () { test() }; call($test2)吗?还是我严重错过了什么:p
  • @pst 当然,但这只是语法糖。匿名函数是使用 Closure 类实现的,所以你实际上是在传递一个对象,而不是一个函数。请注意,函数名称的语法是name,而“匿名函数调用”的语法是$name()。你永远不能在“通过”或匿名函数上使用name()
  • 如果观察到的语义相同,则没有区别。使用“只是没有对象的糖”论点,那么 Scala 或 JavaScript 都不会拥有一流的函数,但它们确实如此。 (function 和可以被视为 function 的对象有什么区别?这取决于语言,但是...)
  • @pst 可以说“一流”是有争议的,但你根本无法做 OP 想做的事。期间。
  • 我不同意。 “为我工作”。查看我的回复。
【解决方案4】:
function func1(){
    echo 'echo1 ';
    return 'return1';
}

function func2($func){
    echo 'echo2 ' . $func();
}

func2('func1');

结果:

echo1 echo2 return1

【讨论】:

  • 如果你能扩展为什么这个工作会很好:) @dhbmarcos
  • 这个答案对于大多数用例来说可能已经足够好了,但对于这个问题是不正确的。想象一下 func1 不能从 func2 的范围内访问。在这种情况下,此解决方案将不起作用。
【解决方案5】:

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

以此为例:

function test ($func) {
    $func('moo');
}

function aFunctionToPass ($str) {
    echo $str;
}

test('aFunctionToPass');

脚本会回显“moo”,就像您直接调用“aFunctionToPass”一样。

【讨论】:

  • 对我来说它给出了一个通知:PHP 通知:使用未定义的常量 aFunctionToPass - 假定为“aFunctionToPass”。当我将函数名作为字符串传递时,通知消失了:test('aFunctionToPass');
  • 嗯,没错。我没有检查警告(我现在把它们关掉了)所以谢谢你。
  • 已更新以修复警告。
【解决方案6】:

这个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

【讨论】:

    【解决方案7】:

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

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

    【讨论】:

    • 这是正确的答案,通过匿名函数。它不使用“变量函数”结构,而是使用 $test 作为对象。顺便说一句,如果你做了 $test = function(){...} 然后 $call = test without (!) 引号你仍然没有得到参考。 $call() 之所以有效,是因为 PHP 允许将不带引号的单词作为字符串,因此它是一个“变量函数”,与 $call = 'test' 相同
    • 更正,我的意思是:如果你做了函数 test(){...} 然后 $call = test 没有 (!) 引号你仍然没有得到参考。
    【解决方案8】:

    你可以说

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

    【讨论】:

    • 这可以通过为test“获取函数对象”来完成吗?喜欢call(function () { test() })? (我不知道这是否可行)。发布的代码的问题是“测试”是一个“未绑定”字符串,并且仅在调用时解析(例如由call_user_function)——此时它可能不同或在不正确的上下文中。
    【解决方案9】:

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

    【讨论】:

      【解决方案10】:

      从 PHP 8.1 开始,您可以使用 First-class callables:

      call(test(...));
      

      你甚至可以使用方法:

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

      就这么简单。

      【讨论】:

        猜你喜欢
        • 2020-10-02
        • 2016-09-10
        • 2022-01-11
        • 2010-11-16
        • 2021-12-11
        • 2012-05-16
        • 1970-01-01
        • 2019-02-12
        • 2015-07-04
        相关资源
        最近更新 更多