如何在 PHP 中传递标签?

How to pass label in PHP?

这个故事的背景很长,所以为了简短起见 -- 我知道 goto 不好,但我别无选择,因为... PHP 缺少逗号运算符.

我有这样的模式——常规函数,入口点作为标签给出,在它里面有一个小的 lambda 需要 goto 到那个入口点。像这样(错误代码):

  function water()
  {
    _Entry_point_2_0:
    // ... some code
    (function() { /*...*/ ;goto _Entry_point_2_0;})();
    // ... some code
  }

我不能直接跳过函数边界,所以我的下一个想法是 return 来自 lambda 的标签,并将其用作 "value" 的 goto。像这样:

  function water()
  {
    _Entry_point_2_0:
    // ... some code
    goto (function() { /*...*/ ;return '_Entry_point_2_0';})();
    // ... some code
  }

这不起作用。将整个 goto 评估为字符串 eval ('goto _Entry_point_2_0;') 也不起作用。

疯狂的是我事先知道标签,所以你可以问为什么我不能这样写整个函数:

  function water()
  {
    _Entry_point_2_0:
    // ... some code
    (function() { /*...*/ ;})();
    goto _Entry_point_2_0;
    // ... some code
  }

问题出在逻辑上——执行 lambda goto 现在生成 2 个表达式,而不是一个。我需要在一个表达式中实现它——执行 lambda 并且 goto 必须打包在一个表达式中。

我也不能递归调用 main 函数,因为这是整个工作的重点,以避免递归调用:-)。

还有哪些其他方法可以实现这一点?

更新 1 也许我换个说法——我想用 goto 实现的是 continue my_function。从内部函数(即 lambda)的边界处执行。

UPDATE 2 主要目标是循环 main 函数,所以它几乎等同于:

  function water()
  {
    _Entry_point_2_0: while (true)
    {
      // ... some code
      continue (function() { /*...*/ ; return '_Entry_point_2_0'; })();
      // ... some code
    }
  }

"Almost"因为两个原因。我仍然和以前一样遇到标签问题,而且现在我有问题在哪里将 breaks 添加到循环中。

你可以使用递归:

function myFunc($i = 0) {
    if ($i < 10) { //or any other logic to prevent "infinite loop"
        //Main code
        myFunc($i++);
    }
}

我相当确定这在设计上是不可能的。

Annonymous functions 要求所有 "state" 通过 use 语句传入。您不能将标签作为参考传递

PHP Parse error: syntax error, unexpected '_Entry_point_2_0' (T_STRING), expecting '&' or variable (T_VARIABLE)

该函数 运行 在它自己的范围内,没有引用标签,这意味着它需要以某种方式传回。

goto docs有以下

This is not a full unrestricted goto. The target label must be within the same file and context, meaning that you cannot jump out of a function or method, nor can you jump into one.

传递变量goto也是无效的

PHP Parse error:  syntax error, unexpected '$goto' (T_VARIABLE), expecting identifier (T_STRING)

尽管所有这一切可能都是好事,因为 goto 表明逻辑流程是错误的,您将能够找到一种更正确且不需要 go to 的方法来构建它。

编辑:

更新2后为什么不做

 if(your lambda() == something) {
        Continue;
 }

抱歉把代码写在我的 phone 上了。这似乎做同样的事情并且更具可读性

因此您不能从 anonymous/lambda 函数中跳过循环迭代。但是您可以 return 一个值,比较主函数中的值,然后从那里跳过迭代。听起来很简单吧?

编辑:如果你也想摆脱兰巴舞,你可以使用相同的策略。

function water() {
    $lambda = function() { /*...*/; };

    while (true) {
        // Call the lambda function and store the return value.
        $return = $lambda();

        // If the return value was 'skip this iteration', well... skip it.
        // Note: I'd normally compare to false, null or similar.
        if ($return == 'skip this iteration') {
            continue;
        }
        elseif ($return == "we're done!") {
            break;
        }

        // Do stuff here.
    }
}

I need to make it in one expression -- execute lambda and goto has to be packed in single expression.

所以从你最后的评论中我现在部分理解了你为什么有这个要求。但目前还不完全清楚。你已经编写了一个脚本来将这段代码注入到一些预先存在的函数中并且不知道周围的环境。但是 goto 标签已经到位了吗?无论如何,也许您的问题就这么简单:您希望代码仅是单个 line。但这是可能的,代码 可以 仅跨越 PHP 中的一行。它不是最漂亮的,但它工作得很好。

function water() {
    while (true) {
        if (function() { /*...*/; }() == 'skip this iteration') { continue; /* Or goto */ }
        // Do stuff here.
    }
}

也许您正在尝试解决您尝试的解决方案而不是您原来的问题。这题有味道XY problem.

_Entry_point_2_0:
    // ... some code
    (function() { /*...*/ ;goto _Entry_point_2_0;})();

像我一样寻找 do while 循环:

do {
    // ... some code
} while ((function() { /*...*/ ; return $k !== 0;})());

现在不允许应用这样的匿名函数。此外,需要显式声明闭包参数。因此我的解决方案需要这样写:

$k = 10;
$f = function() use (&$k) { /*...*/ ; return $k !== 0; };
do {
    // some code
} while ( $f() );

如果你想要一个 "comma operator" 你只需要创建一个函数接受任意数量的参数和 return 最后一个:

function begin(){
    return func_get_args()[func_num_args()-1];
}

begin(expression1, expression2, expression3); // ==> result of expression3

函数的所有参数都会被求值,因此在参数不相互依赖的情况下它会执行相同的操作。