3

When passing a non-existent value by reference, PHP creates the value and sets it to NULL. I noticed it when memory increases were occurring while checking empty values in some functions. Take the following function:

function v(&$v,$d=NULL){return isset($v)?$v:$d;}
$bar = v($foo, $default);

This would be shorthand for:

if(isset($foo))
{
    $bar = $foo;
}
else
{
    $bar = $default;
}

However, when passing non-existent variables PHP creates them. In the case of variables - they are removed as soon as the method/function ends - but for checking super global arrays like $_GET or $_POST the array element is never removed causing extra memory usage.

$request_with = v($_SERVER['HTTP_X_REQUESTED_WITH']);

Can anyone explain why this happens and if it is a PHP todo fix or a feature for some other crazy use of values?

1
  • PHP 5.3.x on Debian, Ubuntu, and Windows XP running PHPFastcgi. Commented Dec 7, 2010 at 19:43

2 Answers 2

3

XeonCross' function v is a shorthand for the often used:

$val= isset($arr['elm']) ? $arr['elm'] : 'default'

to avoid the dreaded 'Undefined index: elm' notice. A nice helper function would be:

function ifset(&$v1, $v2 = null) {
    return isset($v1) ? $v1 : $v2;
}

as Xeoncross suggested, so you could write the much nicer

$val = ifset($arr['elm'],'default') 

however, this has a lot of interesting (?) quirks in our beloved "language" that we call PHP:

inside the function ifset, $v1 seems UNSET, so it correctly returns the value $v2 and you might conclude that ifset works ok. But afterwards $arr['elm'] is silently set to NULL. So consider the following:

    function wtf(&$v) {
       if (isset($v))
           echo "It is set";
       else
           echo "It is NOT set";
    }
    $p=[];
    wtf($p['notexist']);   => It is NOT set
    $p;                    => [ 'notexist' => NULL ]

But this is another delusion, as the isset() function returns false for NULL values as well:

$x=NULL;
isset($x)   => false... huh??

Did we expect this? well.. it is in the documentation, so this is by design as well. Welcome to the wonderful world of php.

Sign up to request clarification or add additional context in comments.

1 Comment

I also created a method exactly like this one. And then I lost half of the day trying to figure out what is creating crappy data in my arrays. :/
2

The reason you have the memory leak, is because you're telling it to.

When you ask for a reference parameter, PHP will provide you with one. When you are calling a function with an unset variable, PHP will set the variable and then pass the reference to that new variable. When you call it with a superglobal, it creates the missing index. That's because you told it to.

However, I must ask why specifically do you need variable references? 99.9% of the time you don't really need them. I suspect that it'll work just fine to do:

function v($v, $d = null) { return isset($v) ? $v : $d; }

Or, if you really must use references (which you can't get around your original problem with), you should also return a reference:

function &v(&$v, $d = null) { 
    if (isset($v)) {
        return $v;
    }
    return $d;
}

Otherwise it's pointless to take a reference and not return one...

2 Comments

Pointless indeed. My only guess is that he thinks he's saving resources by not passing by value. Unfortunately, he's unaware of COW (copy-on-write).
I'm aware of COW, saving memory isn't the point of the function. Dealing with non-existent values is. however, function &v(){...} is invalid PHP: Notice: Only variable references should be returned by reference which is why it's written like it is. In other words, references are the only way to deal with unset values without causing PHP to error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.