Marius
Marius

Reputation: 4016

Unexpected behaviour with undefined array indexes

Can someone explain to me why this strange thing is happening? I have an empty $_POST array and i want to use a variable in that array that might be defined or not (in that case - use some default value). To do so, i have a function to avoid using all those isset() or empty() checks:

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

    return $defaultValue;
}

Now if i say:

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

The $_POST array now contains a NULL value key "test". I assume this is happening because the variable is passed by reference and somehow auto-creates an array index. How could i avoid this behaviour?

Upvotes: 0

Views: 68

Answers (2)

Alma Do
Alma Do

Reputation: 37365

Yes. That will work so because you're using a reference in your function. That will create array index. Shorter way to illustrate:

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

Array is now:

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

So index was created. That's how references work (when creating that references you increase refcount by one).

And - no: it is impossible to implement isset() with a custom user-land function. That is because references in PHP are not pointers. You can not maintain scope with references.

You may use wrapper for arrays like

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;
    }
}

So check if index exist first. Usage is like:

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

Then your array won't have additional indexes after such check. But - this also uses references, it's tricky way and it reduces readability. I strongly recommend to use direct isset() checks instead.

Upvotes: 2

deceze
deceze

Reputation: 522042

That's how call-by-reference works. Take this example:

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

foo('bar', $error);

echo $error;

The point of this pattern is that the variable $error will be created in the calling scope and will be populated with error codes, so you have access to them later. So yes, your array key will be created for you if it doesn't exist.

What you are trying to do is simply nonsensical.

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

The isset check within this function is entirely nonsensical, since $bar is declared right there in the function signature. The variable is absolutely guaranteed to exist. You cannot use this construct to test whether some variable in the calling scope was set or not, whether you pass by reference or not. The variable exists within the function and is entirely independent of anything in the calling scope. You're only passing values into the function, not the variables themselves.

You have to use isset directly on the $_POST array in the calling scope, you cannot defer that into a different scope.

The only alternative is to pass the array and key separately:

val($_POST, 'test')

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

Upvotes: 0

Related Questions