Эмуляция функций goto в PHP 5.2 - может быть, лучший подход?

Я написал сценарий, используя мою локальную установку PHP 5.3 с использованием оператора goto. Загрузив его на свой веб-сервер, я обнаружил, что у моего хостера все еще установлен PHP 5.2, и поэтому он не поддерживает goto. Поэтому у меня вопрос, как имитировать функциональность goto в следующем контексте:

foo();

iterator_start:

foreach ($array as $array_item) {
    switch ($array_item) {
        case A:
            foo();
            break;
        case B:
            // Substitute
            array_splice($array, offset($array_item), 1, array(A, A, B, C));
            // Restart iterator
            goto iterator_start;
            break;
    }
}

Идея состоит в том, что массив должен быть изменен в соответствии с набором правил подстановки. После выполнения правила (которое может изменять любое количество элементов массива в любой позиции, заменять их или даже удалять) все должно начинаться с нуля, потому что весь массив мог измениться непредсказуемым образом (таким образом, правила рекурсивной замены разрешены как Что ж). Решение, которое я использую, когда goto просто переходит к началу цикла после каждой замены, мне кажется очень простым и даже довольно чистым, но, как я уже упоминал, я не могу использовать его на своем веб-сервере.

Есть ли здесь замена для goto, или можно выполнить ту же задачу совершенно другим способом (желательно без изменения слишком большого количества кода)?

Любые идеи приветствуются.


Вежливая просьба. Пожалуйста, избавьте меня от лекций о пользе и опасности goto. Я прочитал PHP и goto выражение, которое будет добавлено в PHP 5.3, и знать о спагетти-коде и всех тех, которые в моде «считались вредными» с 1980-х годов. Обсуждение предполагаемого зла goto не имеет ничего общего с моим вопросом, а рассматривать любую программную конструкцию как «плохой стиль» per se - это просто догма, которой нет места в моей идеологии программирования.


person limulus    schedule 09.07.2011    source источник
comment
Без лекций =) не намного ли проще рекурсивная функция? Вы можете хранить их где-нибудь еще и все такое ... Или слишком много переменных среды?   -  person Rudie    schedule 09.07.2011


Ответы (5)


Вы можете использовать each() в цикле while. Он использует курсор внутреннего массива для извлечения текущего элемента в массиве и перемещения курсора к следующему элементу. При нарезке массива установите курсор на курсор для перезапуска с начала массива на следующей итерации цикла while. Вызов reset(), вероятно, даже не требуется, это, вероятно, побочный эффект _ 3_, поскольку он изменяет массив.

foo();
while (list($key, $array_item) = each($array)) {
  switch ($array_item) {
    case A:
      foo();
      break;
    case B:
      // Substitute
      array_splice($array, offset($array_item), 1, array(A, A, B, C));
      // Reset array cursor, this is probably not necessary 
      reset($array);
      break;
  }
}
person Pierre Buyle    schedule 09.07.2011
comment
Это именно то, к чему я стремился. Большое спасибо! - person limulus; 09.07.2011

Рекурсия? Вместо goto iterator_start вы заключаете этот цикл в функцию и вызываете его рекурсивно.

person Denis Biondic    schedule 09.07.2011
comment
Я бы предпочел сохранить цикл внутри контекста родительской функции, поскольку до и после него должен выполняться код, который имеет логическое соединение с ним, например, подготовка массива (я попытался указать на это, добавив foo() перед петлей). - person limulus; 09.07.2011

Говорят, что любой goto можно заменить управляющими структурами, такими как for и while, или функциями.

В вашем случае я бы использовал для этого функцию:

function goto_substitute($array){

foreach ($array as $array_item) {
    switch ($array_item) {
        case A:
            foo();
            return $array;
        case B:
            // Substitute
            array_splice($array, offset($array_item), 1, array(A, A, B, C));
            // Restart iterator
            return goto_substitute($array) ;                
    }
}
}

Изменить (чтобы исправить комментарий)

Функции делают код более читабельным. В лучших практиках программирования говорится, что функция должна выполнять одну вещь и не должна превышать размер экрана (около 80-90 строк) - у вас есть несколько блоков подстановки - кажется логичным иметь несколько функций - если называть их интуитивно, то каждый поймет, что там происходит

person Tudor Constantin    schedule 09.07.2011
comment
Спасибо, это определенно работает, но мне бы очень не хотелось вводить дополнительные функции. У меня есть около 20 таких циклов подстановки, некоторые из них в одной функции, и это фактически утроило бы количество функций в моем скрипте, что, безусловно, значительно затруднило бы обслуживание и чтение. Однако, если нет другого пути, это действительно было бы выходом. - person limulus; 09.07.2011
comment
+1, особенно из-за дополнительного комментария. Вы должны писать функции для выполнения одной задачи, а не только прибегать к ним, чтобы они действовали только как оператор потока управления. - person GolezTrol; 09.07.2011
comment
Я принял ваш вопрос, потому что он делает то, о чем я просил; тем не менее, в моем частном случае дополнительные функции сделают мой код менее логичным. Каждая из моих функций выполняет одно правило подстановки и названа соответствующим образом. Внутренние циклы не имеют семантического значения, за исключением выполнения части правила подстановки, поэтому результирующие функции будут называться substitution_rule_X_inner_loop_Y, что я не считаю очень логичным или пояснительным. Тем не менее, спасибо за вашу помощь. - person limulus; 09.07.2011

вы пробовали использовать include? Я имею в виду, что вы пишете свой код foreach в файле с именем

foreach.php, как это, вместо использования goto вы просто используете include ('foreach.php') следующим образом:

foreach ($array as $array_item) {
switch ($array_item) {
    case A:
        foo();
        break;
    case B:
        // Substitute
        array_splice($array, offset($array_item), 1, array(A, A, B, C));
        // Restart iterator
        include('foreach.php'); 

        break;
}

}

person CruzDelSur    schedule 09.08.2013

goto - это злой артефакт древних времен. Почему это введено в PHP 5.3, никто не знает. Не используйте это. Всегда.

Вот отличное объяснение Дейкстры, которое даже предполагает, что это было Некоторые неодобрительно относятся к ним с 1959 года. По мере того, как появилось больше операторов потока управления, потребность в goto стала еще меньше. У него могут быть определенные применения при оптимизации низкоуровневого критичного по времени кода, но нет абсолютно никаких причин использовать его в PHP, и мне еще предстоит увидеть первый пример, в котором goto было бы лучше, чем любое другое решение.

В вашем случае рекурсия может быть лучшим решением.

person GolezTrol    schedule 09.07.2011
comment
Да, противники, я знаю, что ОП специально просил не читать лекций. Но давай: Поехали. Даже программисты PHP должны знать, почему не следует использовать goto. Всегда. Существует множество других возможностей для написания нечитаемого и неочищаемого кода на PHP. Для этого вам также не нужен goto. - person GolezTrol; 12.07.2011
comment
Возможно, вы сможете объяснить, почему мы не должны использовать goto? Кроме того, если вы знаете, как его использовать, я не вижу проблем с его использованием. Я лично использую goto в C (а теперь мне пришлось использовать его в PHP), но только внутри функции. - person 0xAF; 22.04.2013
comment
Вот отличное объяснение Дейкстры, которое даже предполагает Некоторые неодобрительно относились к этому с 1959 года. По мере появления большего количества операторов потока управления потребность в goto становилась все меньше. У него могут быть определенные применения при оптимизации низкоуровневого критичного по времени кода, но нет абсолютно никаких причин использовать его в PHP, и мне еще предстоит увидеть первый пример, в котором goto было бы лучше, чем любое другое решение. - person GolezTrol; 23.04.2013
comment
Хорошо, насчет PHP согласен, голос против удален. Тем не менее, в некоторых случаях это довольно полезно (по крайней мере, в C). - person 0xAF; 25.04.2013