【问题标题】:Self-calling anonymous function without declaring as variable不声明为变量的自调用匿名函数
【发布时间】:2015-02-01 13:48:27
【问题描述】:

我想调用一个匿名函数而不为它声明一个变量。

我知道这是一个可行的示例:

$foo = function ($bar) use ($foo) {
    if (is_array($bar)) {
        foreach ($bar AS $current) {
             $foo($current);
        }
    }
    else {
        print($bar);
    }
};

$foo($input);

# Unset variable cause we won't need it anymore
# and we like to have a lot of free memory.
unset($foo);

但我想自动调用并取消设置:

call_user_func(function ($bar) {
    if (is_array($bar)) {
         foreach ($bar AS $current) {
             # This won't work
             # as our function doesn't have any name.
             call_user_func(__FUNCTION__, $current);
         }
    }
    else {
         print($bar);
    }
}, $input);

但是这个例子是行不通的,因为我们的函数没有名字。有什么解决方法或者你知道解决这个问题的方法吗?


PS:假设$input 是以下数组:["Hello, ", "World!"]

至此,输出应该是:

Hello, 
World!

更新 #1:

由于这只是一个示例,call_user_func_array(function () { ... }, $input) 不是我正在寻找的解决方案。

如果我有一个像 [["Hello, ", "World"], "!"] 这样的 $input,它将无法工作。


更新 #2:

寻找的另一个解决方案是debug_backtrace()[1]['args'][0]->__invoke($current);。我认为仅用于 debug 已经够丑了。 :) 感谢@fschmengler

另外一种形式是call_user_func(debug_backtrace()[1]['args'][0], $current));


更新 #3:

@UlrichEckhardt 编写的另一个解决方案是将匿名函数嵌入到另一个匿名函数中。我认为,取消设置先前声明的函数变量 - 例如。第一个例子 - 既干净又短。但这也是一个解决方案。

function () {
    $f = function ($param) use ($f) {
        // use $f here
    }
    return $f;
}()

【问题讨论】:

  • @MichaelBerkowski (function() {...})(); 解决方案会很有趣,但目前还不是实际的。也许唯一可用的解决方案是为 PHP 5.5 - 5.6 制作call_user_anonym_func()。 (?)
  • @MichaelBerkowski 第一个例子是一个有效的例子,它确实如此。但我不想为函数声明一个变量并将其存储在其中(或者unset(),如果它完成了。(这真的没有意义,但我认为这是一个有趣的问题。)
  • 对不起,对不起。当我去搜索相关问题时,我忘记了你说最上面的例子有效。我将删除之前的 cmets。
  • @MichaelBerkowski 没问题! :D
  • 在重新发明轮子之前,你检查过array_walk_recursive()吗?它迭代嵌套数组树并在每个叶子(!)元素上调用一个函数。

标签: php recursion anonymous-function php-5.5


【解决方案1】:

可以使用debug_backtrace() 访问闭包并使用__invoke() 调用它 像以前一样使用call_user_func() 调用它:

$input = ["Hello, ", "World!"];

call_user_func(function ($bar) {
    if (is_array($bar)) {
         foreach ($bar AS $current) {
             call_user_func(debug_backtrace()[1]['args'][0], $current));
         }
    }
    else {
         print($bar);
    }
}, $input);

但在我看来,将闭包分配给变量的第一个版本更具可读性,除了个人喜好之外,我没有看到任何反对它的论据。

更新:它必须是call_user_func(),而不是__invoke(),以便args[0] 引用每个递归级别的闭包

【讨论】:

  • 是的,这是一个接近我正在寻找的解决方案。但是我们应该只将它用于调试(_backtrace ...),所以我不会将它标记为解决方案我正在寻找。谢谢!
【解决方案2】:

写一个闭包返回你想要的闭包并调用它:

function () {
    $f = function ($param) use ($f) {
        // use $f here
    }
    return $f;
}()

我实际上并不相信 PHP 能够一步定义和调用函数,您可能不得不使用 call_user_func() 来解决您的语言的缺点。除此之外,还有更好的方法来编写混淆代码,如果这不是您的目标,甚至可能有更清晰的替代方案。 ;-)

【讨论】:

  • 我写了一个像这样工作的辅助函数call_user_anonym_func()。我会尽快发布。 :) 谢谢!
  • 顺便说一句,这对我来说只是一个有趣的问题。除了了解替代解决方案之外,它没有其他目标。 :)(+,如果有的话,选择最好的作为答案)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-19
  • 2010-09-23
  • 1970-01-01
  • 2019-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多