未定义的数组索引的意外行为

时间:2014-07-14 09:09:08

标签: php arrays

有人可以向我解释为什么会发生这种奇怪的事情吗?我有一个空的$ _POST数组,我想在该数组中使用一个可能被定义的变量(在这种情况下 - 使用一些默认值)。为此,我有一个函数来避免使用所有那些isset()或empty()检查:

function val(&$varToCheck, $defaultValue = false)
{
    if (isset($varToCheck))
        return $varToCheck;

    return $defaultValue;
}

现在,如果我说:

val($_POST['test']); print_r($_POST['test']);

$ _POST数组现在包含一个NULL值键" test"。我假设发生了这种情况,因为变量是通过引用传递的,并以某种方式自动创建数组索引。我怎么能避免这种行为?

2 个答案:

答案 0 :(得分:2)

是。因为您在函数中使用引用,所以这样做会有效。那将创建数组索引。更简洁的说明方式:

$array = [];
$foo = &$array['foo'];

现在是数组:

array(1) {
  ["foo"]=>
  &NULL
}

因此创建了索引。这就是引用的工作方式(在创建引用时,您将refcount增加一个)。

并且 - :使用自定义用户登陆功能无法实现isset()。那是因为PHP中的引用不是指针。您不能使用引用来维护范围。

您可以使用

等数组的包装器
function valArray(array &$array, $index, $defaultValue = false)
{
    if(array_key_exists($index, $array) && !isset($array[$index]))
    {
        //note, having index & having it set isn't same
        $array[$index] = $defaultValue;
    }
}

因此,请先检查索引是否存在。用法如下:

$array = ['foo'=>null];
valArray($array, 'foo', false);
valArray($array, 'bar', true);
//var_dump($array);

然后你的阵列在检查后没有额外的索引。但是 - 这也使用了引用,这是一种棘手的方式,它降低了可读性。我强烈建议您使用直接isset()检查。

答案 1 :(得分:0)

这是如何通过引用进行调用的。举个例子:

function foo($bar, &$error) { ... }

foo('bar', $error);

echo $error;

此模式的要点是变量$error将在调用范围中创建,并将填充错误代码,以便您以后可以访问它们。所以,是的,如果它不存在,你的阵列密钥将会为你创建。

你要做的只是荒谬的。

function foo($bar) {
    isset($bar) ...
}

此函数中的isset检查完全没有意义,因为函数签名中的$bar被声明。该变量绝对保证存在。您不能使用此构造来测试调用范围中的某个变量是否已设置,是否通过引用传递。变量存在于函数中,并且完全独立于调用范围中的任何内容。您只是将传递给函数,而不是变量本身。

您必须直接在调用范围内的isset数组上使用$_POST,不能将其推迟到其他范围。

唯一的选择是单独传递数组和键:

val($_POST, 'test')

function val(array $array, $key) {
    isset($array[$key]) ...
}