4

I have written a script using my local PHP 5.3 installation making use of the goto statement. Uploading it to my webserver, I had to discover that my hoster still has PHP 5.2 installed and therefore doesn't support goto. My question is therefore how to emulate goto's functionality in the following context:

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;
    }
}

The idea is that an array must be modified according to a set of substitution rules. Once a rule has been executed (which may modify any number of array items in any position, replace them, even delete them) everything must start from zero because the entire array may have changed in an unpredictable fashion (thus recursive substitution rules are allowed as well). The solution I use, with goto simply jumping to the start of the loop after each substitution, seems very straightforward and even quite clean to me, but as I mentioned I cannot use it on my webserver.

Is there any substitute for goto here, or can the same task be accomplished in an entirely different manner (preferably without changing too much code)?

Any ideas are appreciated.


A polite request: Please spare me any lectures on the usefulness or dangers of goto here. I've read PHP and the goto statement to be added in PHP 5.3 and know about spaghetti code and all those en vogue "considered harmful" letters from the 1980s. Discussing the supposed evil of goto has nothing to do with my question, and treating any program construct as "bad style" per se is simply dogma, which has no place in my programming ideology.

Community
  • 1
  • 1
limulus
  • 213
  • 2
  • 11
  • Without the lectures =) isn't a recursive function much easier? You can store them some place else and all that... Or are there too many environment variables? – Rudie Jul 09 '11 at 19:38

5 Answers5

2

You can use each() in a while loop. It uses the internal array cursor to retrieve the current element in the array and move the cursor to the next one. When slicing the array, reset to cursor to restart from the start of the array at the next while loop iteration. Calling reset() is probably not even required, it's probably a side effect of array_splice() since it changes the array.

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;
  }
}
Pierre Buyle
  • 4,883
  • 2
  • 32
  • 31
1

Recursion? Instead of goto iterator_start, you wrap this loop in a function, and call it recursively.

Denis Biondic
  • 7,943
  • 5
  • 48
  • 79
  • I'd prefer to keep the loop inside the context of a parent function, since there is code to be executed before and after it that has a logical connection to it, like preparation of the array (I tried to point to that by adding `foo()` before the loop). – limulus Jul 09 '11 at 07:13
1

Well, it is said that any goto can be replaced with control structures like for and while or functions.

In your case, I would use a function for this:

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) ;                
    }
}
}

Edit (to address the comment)

Functions makes code much more readable. Programming best practices says that a function should do a single thing and to not be bigger than a screen in size (around 80-90 lines) - you have multiple substitution blocks - it seems logical to have multiple functions - if you name them intuitively then anybody will understand whats going on there

Tudor Constantin
  • 26,330
  • 7
  • 49
  • 72
  • Thank you, this certainly works, but I would really like not to need to introduce extra functions. I have about 20 substitution loops like this, some of them within the same function, and doing so would effectively triple the number of functions in my script, which certainly would make maintainance and reading much harder. However, if there is no other way, this would indeed be the solution. – limulus Jul 09 '11 at 07:18
  • 1
    +1, especially due to the additional comment. You should write functions to perform a single task, and not only resort to them to act like a control flow statement only. – GolezTrol Jul 09 '11 at 07:32
  • I accepted your question, because it does what I asked for; still, in my special case the extra functions will make my code less logical. Each of my functions executes one substitution rule, and is named accordingly. The inner loops have no semantic meaning except for executing part of the substitution rule, thus the resulting functions would be named `substitution_rule_X_inner_loop_Y` which I don't find very logical or explanatory. Still, thank you for your help. – limulus Jul 09 '11 at 07:34
0

did you try use an include? I mean say you write your foreach code in a file called

foreach.php like this, instead of use goto you just use include('foreach.php') like this:

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;
}

}

CruzDelSur
  • 91
  • 5
-4

goto is an evil artifact of ancient days. Why it is introduced in PHP 5.3, nobody knows. Don't use it. Ever.

Here is a great explanation by Dijkstra that even suggests it has been frowned upon by some since 1959. As more control flow statements arose, there's even less need for goto. It may have specific uses when optimizing some low level, time critical code, but there's absolutely no reason to use it in PHP and I have yet to see the first example where goto would be better than any other solution.

In your case, recursion might be the best solution.

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
  • Yeah downvoters, I know OP specifically asked not to lecture. But c'mon: GOTO. Even PHP programmers must know why you shouldn't use goto. Ever. There are many, many others oppurtunities to write unreadable and unmaintanable code in PHP. You don't need goto for that either. – GolezTrol Jul 11 '11 at 21:27
  • Perhaps you can explain why we should not use goto ? Other than that, if you know how to use it, I see no problems using it. I personally use goto in C (and now I had to use it in PHP), but only inside a function. – 0xAF Apr 22 '13 at 17:39
  • [Here](http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF) is a great explanation by Dijkstra that even suggests it has been frowned upon by some since 1959. As more control flow statements arose, there's even less need for goto. It may have specific uses when optimizing some low level, time critical code, but there's absolutely no reason to use it in PHP and I have yet to see the first example where goto would be better than any other solution. – GolezTrol Apr 23 '13 at 06:21
  • 1
    Ok, Agreed about PHP, removed downvote. Still it's pretty useful in some cases (at least in C). – 0xAF Apr 25 '13 at 08:04