История этой истории довольно длинная, поэтому, если говорить кратко, я знаю, что goto — это плохо, но у меня нет другого выбора, потому что … в PHP отсутствует оператор запятой.
У меня есть такой шаблон — обычная функция с точкой входа, заданной как метка, и внутри нее небольшая лямбда, которая должна goto
к этой точке входа. Примерно так (неверный код):
function water()
{
_Entry_point_2_0:
// ... some code
(function() { /*...*/ ;goto _Entry_point_2_0;})();
// ... some code
}
Я не могу просто перепрыгнуть через границы функций, поэтому моя следующая идея — вернуть метку из лямбды и использовать ее как «значение» для 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
}
Проблема в логике — выполнение лямбды а также сделай 2 выражения сейчас, а не одно. И мне нужно сделать это в одном выражении — выполнить lambda, а goto должен быть упакован в одно выражение.
Я также не могу рекурсивно вызывать основную функцию, потому что в этом и заключается весь смысл этой работы, чтобы избежать рекурсивного вызова :-).
Каковы другие способы достижения этого?
ОБНОВЛЕНИЕ 1 Может быть, я перефразирую — то, что я хотел бы достичь с Goto continue my_function
, Выполняется от или на границе внутренней функции (т.е. лямбда).
ОБНОВЛЕНИЕ 2 Основная цель состоит в том, чтобы перебрать основную функцию, поэтому она почти эквивалентна:
function water()
{
_Entry_point_2_0: while (true)
{
// ... some code
continue (function() { /*...*/ ; return '_Entry_point_2_0'; })();
// ... some code
}
}
«Почти» по двум причинам. У меня все еще есть проблема с ярлыками точно так же, как раньше, и, более того, теперь у меня есть проблема, где добавить break
с петлей.
Возможно, вы пытаетесь решить ваше озадаченное решение, а не исходную проблему. Этот вопрос пахнет XY проблема.
_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() );
Если вы хотите иметь «оператор запятой», вы просто создаете функцию, которая принимает любое количество аргументов и возвращает последнее:
function begin(){
return func_get_args()[func_num_args()-1];
}
begin(expression1, expression2, expression3); // ==> result of expression3
Все аргументы функции оцениваются, поэтому она делает то же самое, учитывая, что аргументы не зависят друг от друга.
Таким образом, вы не можете пропустить итерацию цикла из анонимной / лямбда-функции. Но вы можете вернуть значение, сравнить значения в основной функции, а затем пропустить итерацию оттуда. Звучит просто, правда?
Редактировать: если вы также хотите оторваться от ламбы, вы можете использовать ту же стратегию.
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.
}
}
Мне нужно сделать это в одном выражении — выполнить лямбду, а goto должен быть упакован в одном выражении.
Итак, из вашего последнего комментария я теперь частично понимаю, почему у вас есть это требование. Но это все еще не совсем ясно. Вы написали скрипт для внедрения этого кода в некоторые ранее существующие функции и не знаете окружения. Но ярлыки goto уже на месте? В любом случае, возможно, ваша проблема так проста: вы хотите, чтобы код был единым линия только. Но это возможно, код Можно охватывать только одну строку в PHP. Это не самая красивая, но работает просто отлично.
function water() {
while (true) {
if (function() { /*...*/; }() == 'skip this iteration') { continue; /* Or goto */ }
// Do stuff here.
}
}
Я уверен, что это невозможно по замыслу.
Анонимные функции требует, чтобы все «состояние» передавалось через оператор использования. Вы не можете передать ярлык в качестве ссылки
Ошибка синтаксического анализа PHP: синтаксическая ошибка, непредвиденная ‘_Entry_point_2_0’
(T_STRING), ожидая ‘&’или переменная (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 предполагает, что логический поток неверен, вы сможете найти способ структурировать этот процесс, который является более основательным и не требует перехода.
Редактировать:
После обновления 2 почему бы не сделать
if(your lambda() == something) {
Continue;
}
Извините написал код на моем телефоне. Это, кажется, делает то же самое и гораздо более читабельно
Вы можете использовать рекурсию:
function myFunc($i = 0) {
if ($i < 10) { //or any other logic to prevent "infinite loop"//Main code
myFunc($i++);
}
}