Goto Code in PHP
It's not as bad as you'd think
Sometimes, you just need a way to GOTO. Here is a little trick that will duck out of a section of code using break
The GOTO style of coding, common in languages like BASIC, have been marked by developers as generally a bad idea. It makes code very unreadable by forcing the writer to remember where everything is pointing. It turns your code into a big mess.
Well, some times you need that functionality. Case in point, I found myself creating an SQL query that joined two many-to-many related tables using IDs. The problem was that I was rewriting the query over and over, when I could have just pulled it out into a single query statements that just used variables.
Before:
function addManyToMany($vars) {
$sql = "
SELECT id
FROM table_a
WHERE desc = '{$vars['desc']}'
";
$res = mysql_query($sql);
if(mysql_num_rows($res) == 1) {
$a_id = mysql_results($res, 'id', 0);
$sql = "
INSERT INTO join_table
SET
table_a_id = $a_id,
table_b_id = {$vars['b_id']}
";
return mysql_query($sql);
}
$sql = "
SELECT id
FROM table_a
WHERE desc LIKE '%{$vars['desc']}%'
";
$res = mysql_query($sql);
if(mysql_num_rows($res) == 1) {
$a_id = mysql_results($res, 'id', 0);
$sql = "
INSERT INTO join_table
SET
table_a_id = $a_id,
table_b_id = {$vars['b_id']}
";
return mysql_query($sql);
}
$sql = "
INSERT INTO table_a
SET {$vars['sql']}
";
mysql_query($sql);
$a_id = mysql_insert_id();
$sql = "
INSERT INTO join_table
SET
table_a_id = $a_id,
table_b_id = {$vars['b_id']}
";
return mysql_query($sql);
}
As you can see, the query to insert the many-to-many table entry is the same for each case that I have. The variables are of the same type, and do roughly the same thing. This list of cases could easily grow as time progresses. And the query to insert into the many-to-many table could be changed, which would mean editing many lines of code for just one update.
There is a better way.
After:
function addManyToMany($vars) {
do {
$sql = "
SELECT id
FROM table_a
WHERE desc = '{$vars['desc']}'
";
$res = mysql_query($sql);
if(mysql_num_rows($res) == 1) {
$a_id = mysql_results($res, 'id', 0);
break;
}
$sql = "
SELECT id
FROM table_a
WHERE desc LIKE '%{$vars['desc']}%'
";
$res = mysql_query($sql);
if(mysql_num_rows($res) == 1) {
$a_id = mysql_results($res, 'id', 0);
break;
}
$sql = "
INSERT INTO table_a
SET {$vars['sql']}
";
mysql_query($sql);
$a_id = mysql_insert_id();
} while(false);
$sql = "
INSERT INTO join_table
SET
table_a_id = $a_id,
table_b_id = {$vars['b_id']}
";
return mysql_query($sql);
}
Now all the cases are wrapped in a do while clause. This allows for arbitrary breaks in code which will drop out right above the insert into the many-to-many table. Now there is only one insert query which will greatly improve manageability. The other way to solve this would have been to create a function (maybe a lambda?) that would take in the id's and insert them. But this is just an example of what can be done.



It also reduces the number of return points in the function, which is good coding practice. Nice article.
Left by Bernie Zimmermann | Oct. 11, 2008 at 2:36pm
@Bernie, That's a great point. There in only one return statement, and it's all the way at the bottom, which is where one would expect it.
Left by Paul at SC | Oct. 13, 2008 at 10:27am
Could you please explain, where the GOTO code is in either of the examples? I can't find it!
P.S. what is the point of having
do
{
stuff
}
while(false)
?
Why not just
stuff
???
Left by Confused person | Feb. 6, 2009 at 7:50pm
@Confused
The do{}while() loop is simply a wrapper around the code, allowing the use of break statements within, which simulate a GOTO. Each break within the do wrapper acts in some ways like a GOTO, jumping to the end of said wrapper.
Left by Joe at SC | Feb. 16, 2009 at 9:45am
I found myself doing this another way this morning while helping a friend with some code.
< ?php
switch(true): default:
do-stuff
if(case) break;
do-more-stuff
endswitch;
?>
Left by Paul at SC | Mar. 3, 2009 at 4:39pm
Looks like PHP 5.3 has solved this problem by adding the GOTO function. I'm still conflicted on this. http://us2.php.net/goto
Left by Paul at SC | Jun. 24, 2009 at 10:48am
It is at least a somewhat limited, context-restricted implementation of goto, meaning that you can't jump in and out of files or functions.
Left by Joe at SC | Jun. 30, 2009 at 11:07am
Leave a Comment