我遇到了一些非常奇怪的php行为(ubuntu 10.04上的5.3.2)。应该在本地范围内发生的未设置会影响调用者函数的范围。以下代码片段是我的代码的简化,它显示了我只能假设的错误:
<?php
function should_not_alter($in)
{
$in_ref =& $in['level1'];
should_only_unset_locally($in);
return $in;
}
function should_only_unset_locally($in)
{
unset($in['level1']['level2_0']);
}
$data = array('level1' => array('level2_0' => 'first value', 'level2_1' => 'second value'));
$data = should_not_alter($data); //test 1
//should_only_unset_locally($data); //test 2
print_r($data);
?>
如果运行上述内容,您将看到全局范围内的'first value'
数组中未设置值$data
。但是,如果您注释掉test 1
并运行test 2
,则不会发生这种情况。
我只能假设php不喜欢引用数组元素。在我的代码中,我需要更改$in_ref
- 因此上面代码中$in_ref =& $in['level1'];
行的原因。我意识到删除这一行将解决'first value'
在全局范围内未设置的问题,但这不是一个选项。
任何人都可以确认这是否是php的预期行为?
我怀疑这是一个错误,而不是一个功能,因为这种行为与php处理具有普通(非数组)变量的作用域和引用的方式不一致。例如,使用字符串而不是数组函数should_only_unset_locally()
对全局范围没有影响:
<?php
function should_not_alter($in)
{
$in_ref =& $in;
should_only_unset_locally($in);
return $in;
}
function should_only_unset_locally($in)
{
unset($in);
}
$data = 'original';
$data = should_not_alter($data); //test 1
//should_only_unset_locally($data); //test 2
print_r($data);
?>
test1或test2输出original
正如预期的那样。实际上,即使$data
是一个数组但$in_ref
被引用到整个数组(即$in_ref =& $in;
),那么错误的行为也会消失。
更新
答案 0 :(得分:1)
是的,看起来像个臭虫。
正如函数的名称所暗示的那样,should_not_alter
不应该改变数组,因为它是按值传递的。 (我当然不是仅基于名称 - 它也不应该根据其定义改变任何东西。)
评论$in_ref =& $in['level1'];
使$in
单独离开这一事实似乎进一步证明了这是一个错误。这是一个奇怪的小怪癖。不知道内部会发生什么导致这种情况。
我会在PHP bug跟踪器上提交错误报告。对于它的价值,它仍然存在于5.4.6。
答案 1 :(得分:0)
$data = should_not_alter($data)
此行覆盖$data
数组,返回值为should_not_alter
,即$in
。这是正常行为。
此外,在您创建引用 $in_ref =& $in['level1'];
时,但您没有对其进行任何操作。它对程序输出没有影响。
简答:
在调用unset($in_ref)
函数之前,通过should_only_unset_locally()
删除引用变量。
答案很长:
创建对数组元素的引用时,数组元素将替换为引用。这种行为很奇怪,但它不是一个错误 - 它是语言的一个特征,而且是设计的。
考虑以下PHP程序:
<?php
$a = array(
'key1' => 'value1',
'key2' => 'value2',
);
$r = &$a['key1'];
$a['key1'] = 'value3';
var_dump($a['key1']);
var_dump($r);
var_dump($a['key1'] === $r);
Output:
string(6) "value3"
string(6) "value3"
bool(true)
为$a['key1']
分配值会更改$r
的值,因为它们都引用相同的值。相反,更新$r
将更新数组元素:
$r = 'value4';
var_dump($a['key1']);
var_dump($r);
Output:
string(6) "value4"
string(6) "value4"
该值不在$r
或$a['key']
中 - 这些只是引用。这就像他们都引用了一些幽灵般隐藏的价值。很奇怪,是吗?
对于大多数用例,这是期望和有用的行为。
现在将此应用于您的程序。以下行修改本地$in
数组,并使用引用替换'level1'
元素:
$in_ref = &$in['level1'];
$in_ref
不是$in['level1']
的引用 - 而是它们都引用相同的怪异值。所以当这条线出现时:
unset($in['level1']['level2_0']);
PHP将$in['level1']
视为对怪异值的引用,并删除'level2_0'
元素。由于它是一个参考,因此在should_not_alter()
函数的范围内也可以感受到删除。
解决您的特定问题的方法是销毁引用变量,该变量会自动将$in['level1']
恢复为正常行为:
function should_not_alter($in) {
$in_ref =& $in['level1'];
// Do some stuff with $in_ref
// After you're done with it delete the reference to restore $in['level1']
unset($in_ref);
should_only_unset_locally($in);
return $in;
}