1

I have a small function to get element values from an array/object:

<?php
function element( $ind, &$var, $def = NULL ) {
    echo "inside: ".json_encode(isset($var) ? $var : '<unset>') . PHP_EOL;
    if (isset($var) && is_array($var)) {
        return empty($var[$ind]) ? $def : $var[$ind];
    }
    if (isset($var) && is_object($var)) {
        return empty($var->{$ind}) ? $def : $var->{$ind};
    }
    return $def;
}

echo "var before: ".json_encode(isset($myvar) ? $myvar : '<unset>') . PHP_EOL;
$value = element( 'zz', $myvar, '' );
echo "var after: ".json_encode(isset($myvar) ? $myvar : '<unset>') . PHP_EOL;
echo PHP_EOL;
echo "array before: ".json_encode(isset($myarray) ? $myarray : '<unset>') . PHP_EOL;
$value = element( 'zz', $myarray['yy'], '' );
echo "array after: ".json_encode(isset($myarray) ? $myarray : '<unset>') . PHP_EOL;
echo PHP_EOL;
echo "object before: ".json_encode(isset($myobject) ? $myobject : '<unset>') . PHP_EOL;
$value = element( 'zz', $myobject['yy'], '' );
echo "object after: ".json_encode(isset($myobject) ? $myobject : '<unset>') . PHP_EOL;

My problem is that if the $var passed is an array or an object but is not actually set, then it gets magically created, causing problems down the road:

$ php z.php
var before: "<unset>"
inside: "<unset>"
var after: "<unset>"

array before: "<unset>"
inside: "<unset>"
array after: {"yy":null}

object before: "<unset>"
inside: "<unset>"
object after: {"yy":null}

Any idea why this happens and how to prevent it?

EDIT

Ok I am getting a lot of "don't do that" and "tell somebody else to do something", so I will explain a bit more of the situation. I have a code base of over 300,000 lines of PHP code, which has been using the element() function to get values from all kinds of variables for years (called in more than 800 places) and now all of the sudden there crops up some issues due to the function magically creating variables that are not present. Specific case in point, there is a very large multi-dimensional array $member which was being passed as such:

<?php echo json_encode(element('base_name', $member[$wizard_type], ''); ?>

It is not clear what elements $member[xxx] will have in any given situation, and apparently in some situations it is not set, in which case it would be fine to just use empty string (3rd parameter.) Unfortunately this call actually sets $member[$wizard_type], and then later on code gets executed due to this which should not be.

If I could remove the reference and suppress the errors somehow from within the element() function that would be ok I suppose.

1 Answer 1

2

It's explained in the manual: http://php.net/manual/en/language.references.whatdo.php

Note: If you assign, pass, or return an undefined variable by reference, it will get created.

So

Any idea [...] how to prevent it?

Don't pass as a reference.

There's no way how to prevent that behavior. You have to refactor your code to ensure that result given is what you've expected.

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

7 Comments

When I don't pass as a reference then there is an error but I don't want the caller to have to put "@" on every call, is there a way to prevent the error from inside the element function?
It's because your variables were never created or declared. It's a common error. You should prevent that and don't suppress the error.
I have no control over the existence of these elements, or even if it is an object or an array, that is the purpose of the function -- to handle all cases.
The purpose of a function is receive a value (or not), handle and return (or not). But, ensure that a value is provided to a function is a responsibility of programmer/developer, though. So, do this if(isset($myVar)) { myFunction($myVar); } instead of try to prevent a common behavior from PHP Core.
I see now there is no way to fix my situation, the function never should have been used in this way. This is the correct answer and I am accepting it and moving on now to weeks of rewriting other peoples code. Thanks all.
|

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.