ID:               40610
 User updated by:  Webbed dot Pete at gmail dot com
 Reported By:      Webbed dot Pete at gmail dot com
 Status:           Open
 Bug Type:         Documentation problem
 Operating System: Windows, Linux
 PHP Version:      5.2.1
 Assigned To:      colder
 New Comment:

Yes, a single userland function can take care of all but constants.
Here is a robust workaround (if messy and/or slow) for the undocumented
effect described in this bug report (i.e. that PHP creates array
elements and object properties when pass-by-reference is used).

// For PHP4 compatibility...
if (!function_exists('property_exists')) {
  function property_exists($obj, $property) {
   return array_key_exists($property, get_object_vars($obj));
  }
}

// Pass potentially undefined array keys and object property names
separately else they get auto-created
function varset(&$var,$param,$default='') {
        if (!isset($var))    return $default;
        if (is_scalar($var)) return $var;
        if (is_array($var))  return (array_key_exists($param,$var) &&
isset($var[$param])) ? $var[$param] : $default;
        if (is_object($var)) return (property_exists($var,$param) &&
isset($var->$param)) ? $var->$param : $default;
        die('varset used on NULL or resource');
}

Notes:
1) I'll leave the argument to others over whether it is better to have
a single function when scalars have no need for the second parameter.
:)

2) varsettrue() is not replicated here; it simply adds "&& $var", "&&
$var[$param]" or "&& $var->$param" to the end of each appropriate
test.

3) This example highlights a small inconsistency between
array_key_exists() and property_exists().


Previous Comments:
------------------------------------------------------------------------

[2007-02-24 09:54:47] Webbed dot Pete at gmail dot com

If we require a single function, to *fully* emulate 'isset with
default' (with only two parameters), [EMAIL PROTECTED] is correct.

A compromise is currently required involving separate functions or at
least separate parameters that isolate potential array keys or object
property names.

The above emulations are effective userland emulations.

Further emulations are also helpful, such as emulation of '(isset AND
true) with default', which was noted in an earlier comment. This too
can be emulated through a set of functions. 

It gets messy to do these workarounds, but the resulting application
code is much cleaner.

Instead of coding

$x = (isset($var) && $var) ? $var : $default;
$y = (isset($pref['key']) && $pref['key']) ? $pref['key'] : $default;

one can code

$x = varsettrue($var, $default);
$y = arrsettrue($pref,'key',$default);

by creating function varsettrue() as noted above, and now

function arrsettrue($arr,$key,$default='') {
        if ( isset($arr) && is_array($arr) && array_key_exists($key,$arr) &&
isset($arr[$key]) && $arr[$key] ) return $arr[$key];
        return $default;
}

The 'mess' is encapsulated in a set of userland functions. This frees
coders to write well-protected code that never generates notices.

Perhaps someday there can be built-in functions that accomplish all
this, but for now at least we know there are effective (if slow/messy)
workarounds. I now believe a single userland function may be possible;
will think on that.

------------------------------------------------------------------------

[2007-02-24 09:16:27] [EMAIL PROTECTED]

function foo(&$a) {}
foo($a); // will "create" $a
$b = new stdclass;
foo($b->c); // will "create" the public property "c" 
$d = array();
foo($d['index']); // Will "create" the array index

In each case, it will be assigned to null. Calling isset will return
false because isset() returns false on variables assigned to NULL.
However, there are other functions like array_key_exist() or
property_exist() that are able to detect the NULL value.

Conclusion: there is simply no solution to effectively emulate the
isset() construct with default value using an user land function.



------------------------------------------------------------------------

[2007-02-24 03:20:18] Webbed dot Pete at gmail dot com

Typo on function arrset(). Instead of
    ... return $val;
it should be
    ... return $arr[$key];

------------------------------------------------------------------------

[2007-02-24 00:38:43] Webbed dot Pete at gmail dot com

<<<When you pass a non-existent variable by reference of course it HAS
to be created, or what do you think should be referenced?>>>

Funny thing is, passing a reference to a non-existent normal variable
works fine. Only array elements require something to be created.

If we accept this as a requirement, I believe we arrive at the
following set of conclusions:

What we're declarng here is that
a) isset() is not identical to "is created".
b) A php app has no way to discover if a variable is created.
c) Array elements must be treated distinctly from other variables
whenever the number of created keys is important.
d) For array elements, key references must be carried separately from
value references.

Thus, to accomplish the equivalent of "isset() with default," without
causing side effects, can still be accomplished with some pain. 

It requires separate functions for variables, constants and array
elements. I believe the following patterns would be correct:

function varset(&$val,$default='') {
        if (isset($val)) return $val;
        return $default;
}

function defset($str,$default='') {
        if (defined($str)) return constant($str);
        return $default;
}

function arrset(&$arr,$key,$default='') {
        if ( isset($arr) && is_array($arr) && array_key_exists($key,$arr) &&
isset($arr[$key]) ) return $val;
        return $default;
}

Corrections welcome.

Thanks!

------------------------------------------------------------------------

[2007-02-23 23:38:31] [EMAIL PROTECTED]

Reclassified a docu problem.
When you pass a non-existent variable by reference of course it HAS to
be created, or what do you think should be referenced?

------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
    http://bugs.php.net/40610

-- 
Edit this bug report at http://bugs.php.net/?id=40610&edit=1

Reply via email to