Получение неверного аргумента для foreach в результате передачи по ссылочной переменной - PullRequest
0 голосов
/ 30 июня 2018

Я обновляю кодовую базу, которая использует передачу по ссылке Основная функция

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

Вызов функции

    $sqlUtility->splitSqlFile($pieces, $sql_query);
    foreach ($pieces as $piece) 
    {
      .......
    }

Если вышеупомянутая переменная splitSqlFile (& $ ret, $ sql) имеет перед собой символ «&», программа успешно запускается, но если ее удалить, теперь splitSqlFile ($ ret, $ sql), она начнет возвращаться ошибка «недопустимый аргумент, предоставленный для foreach», и когда я пытаюсь использовать функцию «is_array», чтобы проверить, является ли она массивом, результат всегда будет «NULL».

1 Ответ

0 голосов
/ 30 июня 2018

Почему вы получаете ошибку:

Удалив & из $ret, вы больше не ссылаетесь на переменную в вызове функции. В этом случае $pieces. Поэтому, когда вы выполните foreach для $pieces после вызова функции, произойдет ошибка, потому что $ куски в основном являются нулевой переменной в этой точке.

function splitSqlFile(&$ret,$sql) {
    $ret[] = 'stuff';
}
splitSqlFile($pieces,$sql);
// $pieces will be an array as 0 => 'stuff'
foreach ($pieces as $piece) { } // will not error

против

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

Альтернатива без ссылки:

Так что, если вы хотите удалить & и больше не передавать по ссылке, вам нужно внести другие изменения в функцию, чтобы вернуть это значение обратно. И в зависимости от кодовой базы это может означать большую работу везде, где используется функция!

* * 1 022 Пример: * 1 023 *
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) { }

Второй пример (передача массива по ходу дела ... сбивает с толку):

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

Как вы можете видеть, он не только изменяет возвращаемые значения, с которыми нужно иметь дело, но также меняет способ его вызова. Опять же, если эта функция используется в тысяче мест в коде ... серьезные головные боли!

Вывод:

Я бы честно сохранил ссылку как есть. Это было сделано таким образом, чтобы сделать накопление отладочных данных более простым и прямым. В противном случае у вас будет много изменений кода, чтобы избавиться от ссылки.

Однако это может быть просто моим мнением по этому вопросу.

...