Click to See Complete Forum and Search --> : [Resolved] Bug or not - func returning static reference


Drakla
07-07-2005, 12:03 PM
Would you consider this a bug, or at least unexpected behaviour?

php 4.3.10 windows, and 4.3.9 nixxy both give the same output function &gooGoo()
{
static $y = 'Y Static Initial val';
echo "gooGoo Y: $y<br>";
return $y;
}

$foo = &gooGoo(); $foo = 'Change one'; // yes, expect change
$foo = gooGoo(); $foo = 'Second change'; // don't expect change - but there IS
$baz = gooGoo(); $baz = 'Third go'; // don't expect change - and there isn't
gooGoo();

drew010
07-07-2005, 01:48 PM
Its expected since you are returning by reference...

It may be a little clearer like this, i think


<?php
function &gooGoo()
{
static $y = 'Y Static Initial val';
echo "gooGoo Y: $y<br>";
return $y;
}

$foo = &gooGoo(); //return reference of $y to $foo
$foo = 'Change one'; //foo points to the same address as $y,
//so the value "changes" for both

$foo = gooGoo(); //reference still exists, technically you dont even
//need the assignment. gooGoo() would do the same
$foo = 'Second change'; //foo still points to address of $y

$baz = gooGoo(); //$y = 'Second change' return this value to $baz
$baz = 'Third go'; //$baz does not point to $y or $foo so they wont change
//if you did $baz =& gooGoo(); it would change the reference

gooGoo(); //no changes in reference. $y and $foo still point to same place

?>

laserlight
07-07-2005, 02:03 PM
Here's my interpretation:

1. On the first call to gooGoo(), $foo becomes an alias for $y in gooGoo().
2. When $foo is set to 'Change one', $y in gooGoo() is also set to 'Change one'.
3. In the 2nd call to gooGoo(), 'Change one' is printed since that's the value of $y.
$foo = gooGoo() effectively assigns $y to $foo - but $foo already is $y, so there's no net effect.
4. When $foo is set to 'Second change', $y in gooGoo() is also set to 'Second change'.
5. In the 3rd call to gooGoo(), 'Second change' is printed since that's the value of $y.
$baz = gooGoo() assigns the value of $y to $baz.
6. When $baz is set to 'Third go', $y remains set to 'Second change' since $baz is not an alias for $y.
7. In the 4th call to gooGoo(), 'Second change' is print since that's the value of $y.

Basically the ampersand must be used in both the function definition and function call for return by reference (http://www.php.net/manual/en/language.references.return.php) to work as expected.

Drakla
07-07-2005, 03:49 PM
Originally posted by laserlight
Here's my interpretation:

3. In the 2nd call to gooGoo(), 'Change one' is printed since that's the value of $y.
$foo = gooGoo() effectively assigns $y to $foo - but $foo already is $y, so there's no net effect.

Basically the ampersand must be used in both the function definition and function call for return by reference (http://www.php.net/manual/en/language.references.return.php) to work as expected. My interpretation when I found this was the same as point 3. Really foo should be set to a COPY of $y, not a reference on its 2nd call as the ampersand isn't used, so the internal $y shouldn't change on $foo = 'second change', and this is illustrated when $baz is assigned.

I'm going to write another experiment that allows the changing of the static y with via a different path and see if it splits the reference count and what I would consider the same.

drew010
07-07-2005, 04:18 PM
after you return by reference one time from a function to a variable, the reference remains in place.

i.e.


function &x()
{
static $x = 0;
++$x;
echo "func \$x = $x<br />\n";
return $x;
}

$xx =& x(); //$xx = 1, $x = 1 $xx points to the same addr as $x

x(); //$xx = 2 $x = 2
x(); //$xx = 3 $x = 3

++$xx; //$xx = 4; $x = 4

x();

echo $xx; //outputs 5

Drakla
07-07-2005, 04:54 PM
Hi Drew. I know about the reference staying in place, but what was fooling me in my example was the second assignment to $foo without the ampersand. It looks like it shouldn't work, you're not assigning by reference the 2nd time, so how does a change of $foo change $y - this now explains it and puts the beast to sleep in my head, it was nothing to do with reference counting or anything that I tried explaining it with, essentially a 'trick of the light'.<?php
function &gooGoo($returnString = 0)
{
static $yStatic = 'Y Static Initial val';

echo "gooGoo Y: $yStatic <br>";

if ($returnString)
{
echo ' you want string, you get string<br />';

$yStatic = 'change by string condition';

return 'Hi, I am returned string';
}
else
return $yStatic;
}

$proxy = &gooGoo(); // get a control reference to $yStatic

$foo = &gooGoo(); // $foo a definite reference to $yStatic
$foo = 'Change one'; // so $yStatic = 'Change one';

$foo = gooGoo(1);
/* Above I now know $foo equals 'Hi, I am a returned string'
and I assume $yStatic now to be 'change by string condition'
but check it out and it's NOT.

$foo = gooGoo(1) the 2nd time essentially behaves as
$yStatic = 'Hi, I am a returned string' because
$foo IS $yStatic - the eye is just fooled by $foo = gooGoo(1);
*/

echo "\$foo = $foo<br />";
echo '\$proxy = ', $proxy, '<br />';

$foo = 'Second change'; // surely no change - but there IS [though now understood]

$baz = gooGoo();
$baz = 'Third go'; // don't expect change - and there isn't, and never was

gooGoo();
?>