Lor*_*yer 6 php arrays foreach pass-by-reference
我知道,在foreach中通过引用传递项目可能很危险.
特别是,必须不重用通过引用传递的变量,因为它会影响$array,如下例所示:
$array = ['test'];
foreach ($array as &$item){
$item = $item;
}
$item = 'modified';
var_dump($array);
Run Code Online (Sandbox Code Playgroud)
array(1){[0] =>&string(8)"modified"}
现在这里咬我:在函数内部修改数组的内容should_not_modify,即使我没有传递$arrayby值.
function should_not_modify($array){
foreach($array as &$item){
$item = 'modified';
}
}
$array = ['test'];
foreach ($array as &$item){
$item = (string)$item;
}
should_not_modify($array);
var_dump($array);
Run Code Online (Sandbox Code Playgroud)
array(1){[0] =>&string(8)"modified"}
我很想通过我的整个代码库并unset($item);在每个代码库之后插入foreach($array => &$item).
但是,由于这是一项重大任务并且引入了一条可能无用的线路,我想知道是否有一条简单的规则可以知道什么时候foreach($array => &$item)是安全的,而不是unset($item);在它之后,什么时候没有.
编辑以澄清
我想我明白了会发生什么以及为什么.我也知道最好做什么:foreach($array as &$item){...};unset($item);
我知道这是危险的foreach($array as &$item):
$item我的问题是:是否有其他危险的案例,我们是否可以建立一份危险的详尽清单.或者反过来说:是否有可能描述它何时不危险.
首先,关于PHP的两种行为的一些(可能是显而易见的)澄清:
foreach($array as $item)$item循环后将保持变量不变.如果变量是一个引用,就像在foreach($array as &$item),它将"指向"数组的最后一个元素,即使在循环之后.
当变量是引用时,则赋值,例如$item = 'foo';将改变引用所指向的内容,而不是变量($item)本身.这也适用于随后的真实foreach($array2 as $item)这将治疗$item如果它已被如此创建作为基准,因此无论参考指向(在先前使用的阵列的最后一个元素将修改foreach在这种情况下).
显然这很容易出错,这就是为什么你应该总是unset使用a中的引用foreach来确保后续写入不修改最后一个元素(如类型数组的doc的示例#10).
值得注意的是 - 正如@iainn的评论中指出的那样 - 你的例子中的行为与之无关foreach.仅存在对数组元素的引用将允许修改此元素.例:
function should_not_modify($array){
$array[0] = 'modified';
$array[1] = 'modified2';
}
$array = ['test', 'test2'];
$item = & $array[0];
should_not_modify($array);
var_dump($array);
Run Code Online (Sandbox Code Playgroud)
将输出:
array(2) {
[0] =>
string(8) "modified"
[1] =>
string(5) "test2"
}
Run Code Online (Sandbox Code Playgroud)
这无疑是非常令人惊讶的,但在PHP文档"什么参考文献中"中进行了解释.
但请注意,数组内部的引用可能存在危险.使用右侧的引用执行正常(非引用)赋值不会将左侧转换为引用,但是在这些正常赋值中保留数组内的引用.这也适用于通过值传递数组的函数调用.[...]换句话说,数组的引用行为是逐个元素定义的; 各个元素的引用行为与数组容器的引用状态分离.
使用以下示例(复制/粘贴):
/* Assignment of array variables */
$arr = array(1);
$a =& $arr[0]; //$a and $arr[0] are in the same reference set
$arr2 = $arr; //not an assignment-by-reference!
$arr2[0]++;
/* $a == 2, $arr == array(2) */
/* The contents of $arr are changed even though it's not a reference! */
Run Code Online (Sandbox Code Playgroud)
认识到建立一个基准,例如,当是很重要的$a = &$b,然后都$a和$b相等.$a没有指向,$b反之亦然.$a并$b指向同一个地方.
所以,当你这样做时,$item = & $array[0];你实际上$array[0]指向同一个地方$item.由于$item是全局变量,并且数组内的引用被保留,因此$array[0]从任何地方(甚至从函数内部)进行修改都会全局修改它.
还有其他危险的案例,我们是否可以建立一份危险的详尽清单.或者反过来说:是否有可能描述它何时不危险.
我将再次重复PHP文档中的引用:"数组内部的引用具有潜在的危险性".
所以不,不可能描述它何时不危险,因为它永远不会危险.很容易忘记$item已经创建为引用(或者创建并且未被销毁的全局引用),并在代码中的其他地方重用它并破坏数组.这一直是争论的话题(例如在这个bug中),人们称之为bug或者特征......