7

我遇到了一些非常奇怪的 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;),那么错误的行为就会消失。

更新

我已经提交了一个错误报告

4

2 回答 2

1

是的,看起来像一个错误。

正如函数名称所暗示的那样,should_not_alter不应更改数组,因为它是按值传递的。(我当然不是基于名称——它也不应该根据它的定义改变任何东西。)

$in_ref =& $in['level1'];评论使它不理会的事实$in似乎进一步证明了它是一个错误。这是一个相当奇怪的小怪癖。不知道内部可能发生什么导致这种情况。

我会在 PHP 错误跟踪器上提交错误报告。对于它的价值,它仍然存在于 5.4.6 中。

于 2012-12-28T04:36:58.803 回答
1
$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;
}
于 2012-12-28T04:25:36.723 回答