Как передать label в PHP?
предыстория этой истории довольно длинная, так что короче говоря-я знаю, что Гото плох, но у меня нет другого выбора, потому что... В PHP отсутствует оператор запятой.
У меня есть такой паттерн-регулярная функция с точкой входа, заданной как метка, и внутри нее маленькая лямбда, которая должна
goto к этой точке входа. Что-то вроде этого (неверный код): function water()
{
_Entry_point_2_0:
// ... some code
(function() { /*...*/ ;goto _Entry_point_2_0;})();
// ... some code
}
Я не могу просто перепрыгнуть через границы функций, поэтому моя следующая идея-вернуть метку из лямбды и использовать его как "ценность" для Гото. Что-то вроде этого:
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 выражения, а не одно. И мне нужно сделать это в одном выражении-выполнить лямбду и Гото должен быть упакован в один выражение.
Я также не могу рекурсивно вызвать основную функцию, потому что это весь смысл этой работы, чтобы избежать рекурсивного вызова :-).
Каковы другие способы достижения этой цели?
Обновление 1 возможно, я перефразирую - чего я хотел бы достичь с помощью goto, это continue my_function. Выполняется от или на границе внутренней функции (т. е. лямбда).
UPDATE 2 основная цель состоит в том, чтобы замкнуть основную функцию, поэтому она почти эквивалентна кому:
function water()
{
_Entry_point_2_0: while (true)
{
// ... some code
continue (function() { /*...*/ ; return '_Entry_point_2_0'; })();
// ... some code
}
}
"почти" по двум причинам. У меня все еще есть проблема с метками точно так же, как и раньше, и более того, теперь у меня есть проблема, где добавить breaks в цикл.
4 ответов:
Возможно, вы пытаетесь решить свою попытку решения, а не свою первоначальную проблему. Этот вопрос пахнет 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Все аргументы функции вычисляются таким образом, что она делает то же самое, учитывая, что аргументы не зависят друг от друга.
Таким образом, вы не можете пропустить итерацию цикла из анонимной/лямбда-функции. Но вы можете вернуть значение, сравнить значения в главной функции, а затем пропустить итерацию оттуда. Звучит просто, правда?
Edit: если вы также хотите вырваться из Ламбы, вы можете использовать ту же стратегию.
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. } }
Я совершенно уверен, что это невозможно по замыслу.
Анонимные функции требуют, чтобы все "состояния" передавались через оператор use. Вы не можете передать метку в качестве ссылки
PHP Parse error: синтаксическая ошибка, неожиданный '_Entry_point_2_0' (T_STRING), ожидая ' & ' или переменную (T_VARIABLE)
Функция работает в своей собственной области видимости без ссылки на метку, что означает, что ее нужно будет каким-то образом передать обратно.
Гото документы имеют следующий вид
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)Хотя все это, вероятно, хорошо, поскольку Гото предполагает, что логический поток ошибочен, вы сможете найти способ структурировать это, который является более точным и не требует перехода.
Правка:
После обновления 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++); } }
Comments