我遇到了一些非常奇怪的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);
?>
Run Code Online (Sandbox Code Playgroud)
如果运行上面的内容,您将看到该值'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);
?>
Run Code Online (Sandbox Code Playgroud)
test1或test2都original按预期输出.实际上,即使$data是一个数组但是$in_ref引用了整个数组(即$in_ref =& $in;),那么有缺陷的行为就会消失.
更新
$data = should_not_alter($data)
Run Code Online (Sandbox Code Playgroud)
该行使用$data的返回值覆盖数组should_not_alter,即$in。这是正常行为。
另外,当您创建引用时$in_ref =& $in['level1'];,您并没有对其进行任何操作。它不会影响程序的输出。
简短回答:
unset($in_ref)在调用函数之前删除引用变量via 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)
Run Code Online (Sandbox Code Playgroud)
为 赋值会$a['key1']更改 的值,$r因为它们都引用相同的值。相反,更新$r将更新数组元素:
$r = 'value4';
var_dump($a['key1']);
var_dump($r);
Output:
string(6) "value4"
string(6) "value4"
Run Code Online (Sandbox Code Playgroud)
该值不存在于$ror $a['key']- 这些只是参考。就好像他们都在引用一些令人毛骨悚然的隐藏价值。很奇怪吧?
对于大多数用例来说,这是期望且有用的行为。
现在将其应用到您的程序中。以下行修改本地$in数组并'level1'用引用替换该元素:
$in_ref = &$in['level1'];
Run Code Online (Sandbox Code Playgroud)
$in_ref不是对$in['level1']- 相反,它们都引用相同的幽灵值。所以当这条线出现时:
unset($in['level1']['level2_0']);
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)