PHP正在访问嵌套数组以复制它们吗?

时间:2019-02-19 10:24:09

标签: php arrays reference

让我说我有一个数组(它实际上可以有任何深度):

$arr = array(
  "lvl1" => array(
    "lvl2 => ...
  )
)

现在在函数中,我需要像这样访问它:

$path = array("lvl1", "lvl2", ...); // array of ordered indexes
$tmp = $arr;
foreach($path as $lvl){
  ...// other read-only/copy stuff happening on the array, no editing
  $tmp = $tmp[$lvl];
}

在这一点上,出于好奇(这里没有真正的优化),我是否每次都制作份副本?还是只是自动使用引用?

1 个答案:

答案 0 :(得分:2)

TL; DR如果您使用的是PHP 7,除非您进行更改,否则不会在内部复制该数组。这称为写时复制

要了解PHP的工作原理,您可以阅读Reference Counting Basics

  

PHP变量存储在称为“ zval”的容器中。

     

PHP足够聪明,不必在不需要时复制实际的变量容器。

让我们尝试使用debug_zval_dump在简化示例中对此进行说明:

$array = [
        'lvl1' => [
                'lvl2' => [
                        'lvl3' => [
                        ],
                ],
        ],
];

$path = ['lvl1', 'lvl2', 'lvl3'];

$tmp = $array;

foreach ($path as $lvl) {
        debug_zval_dump($array);

        $tmp = $tmp[$lvl];
}

debug_zval_dump($array);

如果运行此代码,您将获得以下输出:

array(1) refcount(4){
  ["lvl1"]=>
  array(1) refcount(1){
    ["lvl2"]=>
    array(1) refcount(1){
      ["lvl3"]=>
      array(0) refcount(1){
      }
    }
  }
}
array(1) refcount(3){
  ["lvl1"]=>
  array(1) refcount(2){
    ["lvl2"]=>
    array(1) refcount(1){
      ["lvl3"]=>
      array(0) refcount(1){
      }
    }
  }
}
array(1) refcount(3){
  ["lvl1"]=>
  array(1) refcount(1){
    ["lvl2"]=>
    array(1) refcount(2){
      ["lvl3"]=>
      array(0) refcount(1){
      }
    }
  }
}
array(1) refcount(3){
  ["lvl1"]=>
  array(1) refcount(1){
    ["lvl2"]=>
    array(1) refcount(1){
      ["lvl3"]=>
      array(0) refcount(2){
      }
    }
  }
}

请注意refcount:它会发生变化,因此在内部PHP会通过引用进行分配,直到您实际更改分配的值为止。您可以在the blog post by nikic中阅读有关内容:

  

与PHP 5的重要区别在于,即使有些变量是PHP引用,而有些不是PHP引用,所有变量都可以共享同一数组。只有执行某种修改后,阵列才会被分离。