note 42456 deleted from control-structures.break by felipe
| From: | felipe@php.net | Date: | Tue, 29 Jan 2008 11:26:46 +0000 |
| Subject: | note 42456 deleted from control-structures.break by felipe | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-135529@lists.php.net to get a copy of this message | ||
Note Submitter: abodeman at yahoo
----
The use of "break n" to break out of n enclosing blocks is generally a pretty dangerous
idea. Consider the following.
Let's say you have a text file that contains some lines of text, as most text files do.
Let's also say that you are writing a little piece of PHP to parse each line and interpret it
as a string of commands. You might first write some test code just to interpret the first character
of each line, like this:
<?php
$num = 0;
$file = fopen("input.txt", "r");
while (!feof($file)) {
$line = fgets($file, 80);
switch ($line{0}) {
// Arbitrary code here--the details aren't important
case 'i': // increment
echo ++$num." ";
break;
case 'f': // find factors
for ($factor = 1; $factor <= $num; ++$factor) {
if ($num % $factor == 0) {
echo "[".$factor."] ";
// stop processing file if 7 is a factor
if ($factor == 7)
break 3; // break out of while loop
}
}
}
}
fclose($file);
?>
So, now that you have this magnificent piece of test code written and working, you would want to
make it parse all the characters in each line. All you have to do is put a loop around the switch
statement, like so:
<?php
$num = 0;
$file = fopen("input.txt", "r");
while (!feof($file)) {
$line = fgets($file, 80);
for ($i = 0; $i < strlen($line); ++$i) {
switch ($line{$i}) {
// Arbitrary code here--the details aren't important
case 'i': // increment
echo ++$num." ";
break;
case 'f': // find factors
for ($factor = 1; $factor <= $num; ++$factor) {
if ($num % $factor == 0) {
echo "[".$factor."] ";
// stop processing file if 7 is a factor
if ($factor == 7)
break 3; // break out of while loop
}
}
}
}
}
fclose($file);
?>
(Of course, you changed "$line{0}" to "$line{$i}", since you need to loop over
all the characters in the line.)
So now you go and try it out, and it doesn't work. After a bunch of testing, you discover that
when 7 is a factor, the code stops processing the current line, but continues to process the
remaining lines in the file. What happened?
The problem is the "break 3;". Since we added another loop, this doesn't break out of
the same loop it did before. In a small program like this, it's not too difficult to find this
problem and fix it, but imagine what it would be like if you have thousands of lines of PHP with a
numbered break statement hidden in the mess somewhere. Not only do you have to find it, you also
have to figure out how many layers you want to break out of.
Unfortunately, PHP doesn't really offer any alternative to numbered break statements. Without
line labels, there's no way to refer to a specific loop. There is also no "goto"
statement in PHP. You could kludge your way around things with something like
<?php
do {
// some code
if ($condition)
break;
// some more code
} while (FALSE);
?>
or
<?php
switch ($dummy) {
default:
// some code
if ($condition)
break;
// some more code
}
?>
but these sorts of tricks quickly add an enormous amount of clutter to your code.
Thus, the moral of the story is simply to be very careful when using numbered break statements. The
numbered break statement is one of the few language features that can break silently when other code
is changed.