4
votes

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.

5
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

5 Answers

2
votes

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

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

1
votes

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

0
votes

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

}

-4
votes

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.