Reputation: 87
I am upgrading a codebase that makes use of pass by reference Main function
function splitSqlFile(&$ret, $sql)
{
$sql = trim($sql);
$sql_len = strlen($sql);
$char = '';
$string_start = '';
$in_string = false;
for ($i = 0; $i < $sql_len; ++$i) {
$char = $sql[$i];
if ($in_string) {
for (;;) {
$i = strpos($sql, $string_start, $i);
if (!$i) {
$ret[] = $sql;
return true;
}else if ($string_start == '`' || $sql[$i-1] != '\\'){
......
}else {
......
} // end if...elseif...else
} // end for
}
else if ($char == ';') {
$ret[] = substr($sql, 0, $i);
$sql = ltrim(substr($sql, min($i + 1, $sql_len)));
$sql_len = strlen($sql);
if ($sql_len) {
$i = -1;
} else {
// The submited statement(s) end(s) here
return true;
}
}else if (($char == '"') || ($char == '\'') || ($char == '`')) {
$in_string = true;
$string_start = $char;
} // end else if (is start of string)
// for start of a comment (and remove this comment if found)...
else if ($char == '#' || ($char == ' ' && $i > 1 && $sql[$i-2] . $sql[$i-1] == '--')) {
......
if (!$end_of_comment) {
// no eol found after '#', add the parsed part to the returned
// array and exit
$ret[] = trim(substr($sql, 0, $i-1));
return true;
} else {
.....
} // end if...else
} // end else if (is comment)
} // end for
// add any rest to the returned array
if (!empty($sql) && trim($sql) != '') {
$ret[] = $sql;
}
return true;
}
Calling the function
$sqlUtility->splitSqlFile($pieces, $sql_query);
foreach ($pieces as $piece)
{
.......
}
If the above variable splitSqlFile(&$ret, $sql) have the "&" before it, the program does run successfully, but if it is removed, now splitSqlFile($ret, $sql), It will start returning the 'invalid argument supplied for foreach' error.and when I try using the "is_array" function to check if it is an array, the result is always "NULL".
Upvotes: 0
Views: 77
Reputation: 4104
Why you get the error:
By removing the &
from $ret
, you are no longer referencing the variable in the function call. In this case, $pieces
. So when you do a foreach
on $pieces
after calling the function, it will error because $pieces is basically a null variable at that point.
function splitSqlFile(&$ret,$sql) {
$ret[] = 'stuff';
}
splitSqlFile($pieces,$sql);
// $pieces will be an array as 0 => 'stuff'
foreach ($pieces as $piece) { } // will not error
vs:
function splitSqlFile($ret,$sql) {
$ret[] = 'stuff';
}
splitSqlFile($pieces,$sql);
// $pieces will be a null variable, since it was never assigned anything
foreach ($pieces as $piece) { } // will error
Alternative to no reference:
So if you want to remove the &
and no longer pass by reference, you have to do other changes to the function to get that value back out. And depending on the codebase, this could mean a whole lot of work everywhere that function is used!
Example:
function splitSqlFile($sql) {
$ret = [];
$ret[] = 'stuff';
return array('result'=>true,'ret'=>$ret);
}
// $result will contain multiple things to utilize
// if you will only need that variable once (does not accumulate)
$result = splitSqlFile($sql);
foreach ($result['pieces'] as $piece) { }
// if that variable is added by multiple calls, and displayed later... merge
$pieces = [];
$result = splitSqlFile($sql_1);
$pieces = array_merge($pieces,$result['pieces']);
$result = splitSqlFile($sql_2);
$pieces = array_merge($pieces,$result['pieces']);
foreach ($pieces as $piece) { }
A second example (passing in the array as you go... gets confusing):
function splitSqlFile($pieces_in,$sql) {
$pieces_in[] = 'stuff';
return array('result'=>true,'pieces_out'=>$pieces_in);
}
$pieces = [];
$result = splitSqlFile($pieces,$sql_1);
$pieces = $result['pieces_out'];
$result = splitSqlFile($pieces,$sql_2);
$pieces = $result['pieces_out'];
foreach ($pieces as $piece) { }
As you can see, not only does it change the return values that has to be dealt with, but it also changes how it is called. Again, if this function is used in a thousand places in the code... serious headaches!
Conclusion:
I would honestly keep the reference as it is. It was done that way to make accumulating debug data easier, and direct. Otherwise you have a lot of code changes to do toget rid of the reference.
However that can simply be my opinion on the matter.
Upvotes: 1