在PHP 7中处理foreach by-ref

jit*_*hit 4 php arrays foreach pass-by-reference php-7

到目前为止,我们一直在使用PHP 5.5,所有代码似乎都流得太好了.由于将其升级为7,因此大多数foreach()似乎都具有不一致的行为.

例如:考虑下面的代码:

$array = array('a', 'b', 'c');
self::testForeach($array);
.
.
.
// $array is passed by reference
public static function testForeach(&$array) {

  foreach ($array as $key => $val) {
    //produces a, b as an output in PHP 5
    //produces a, b, c as an output in PHP 7
    var_dump($val);

    if ($val == 'b') {
      //remove 'c' from the array
      unset($array[2]);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

PHP 5.5中的行为:

$ array通过引用传递给testForeach()函数.因此,从循环内的$数组中删除"c"将直接修改原始数组.因此,迭代值将是a,b而不是c,因为它从中间的数组中移除.

PHP 7中的行为:

$ array通过引用传递给testForeach()函数.当$ array循环遍历foreach()时,会产生一个副本,比如$ arrayCopy(根据doc),它正在循环中迭代.因此从$ array中删除"c"值将没有任何效果,并将循环$ arrayCopy中包含的所有值.因此输出 - a,b,c.

将foreach更改为pass-by-ref对我来说不是一个解决方案,因为我的项目中有太多的foreach并且我无法grep并修改它们中的每一个.

在最新版本上是否对此类行为进行了其他处理.任何可以突出显示它们的工具/解析器?

任何提示/想法?

谢谢!

klo*_*oma 6

只有通过引用循环数组: foreach($ array as $ key =>&$ val){

Afaik然后没有副本正在制作. http://php.net/manual/en/control-structures.foreach.php

警告:在这种情况下,$ val仍然是指向数组最后一个元素的指针,最佳做法是取消它.

foreach ( $array as $key => &$val ) {


<?php

$array = array();
testForeach( $array );

// $array is passed by reference
function testForeach( &$array )
{
    $array = array( 'a', 'b', 'c' );
    foreach ( $array as $key => &$val ) {
        //produces a, b as an output in PHP 5
        //produces a, b, c as an output in PHP 7
        var_dump( $val );

        if ( $val == 'b' ) {
            //remove 'c' from the array
            unset( $array[ 2 ] );
        }
    }
    unset($val);
}
Run Code Online (Sandbox Code Playgroud)


gms*_*tos 3

除了在迭代时修改数组似乎很奇怪之外,在 PHP 7 中,您可以在迭代变量中强制引用:

$array = array('a', 'b', 'c');
foreach ($array as $key => &$val) {
  var_dump($val);
  if ($val == 'b') {
    //remove 'c' from the array
    unset($array[2]);
  }
}
Run Code Online (Sandbox Code Playgroud)

将在 PHP 5 和 7 上返回:

string(1) "a"
string(1) "b"
Run Code Online (Sandbox Code Playgroud)

请参阅3v4l.org上的实际操作。