dongqiaozhe5070 2018-06-29 22:16
浏览 143
已采纳

由于引用变量传递,为foreach提供了无效参数

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".

  • 写回答

1条回答 默认 最新

  • donvo24600 2018-06-29 22:58
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算