Miroshko
Miroshko

Reputation: 873

PHP ignores passing by reference if var is assigned in function call

I have two functions

function c( &$x )
{
    $x = 25;
    echo 'c is called, x = ' . $x . PHP_EOL;
}

function b()
{
    echo 'b is called'. PHP_EOL;
    return 5;
}

Then I write the following code which as I expect should put result of b() to $o, then pass $o by reference to c() where it is set to the new value. it works ok:

$o=b();
c( $o );
echo 'o is '.$o;

the output is as expected:

b is called
c is called, x = 25
o is 25

But if I try to assign value of $o in function call like this:

c( $o = b() );
echo 'o is '.$o;

I get weird output

b is called
c is called, x = 25
o is 5

the order of function calls is still the same but why $o is not changed in spite of it was passed by reference? Does PHP compulsorily passes argument by value if it is assigned in function call? If yes, since what version had this been working that way? According to this comment: http://www.php.net/manual/en/functions.arguments.php#71198 in 2006 it worked differently. My version is 5.3.6

Upvotes: 4

Views: 695

Answers (1)

DaveRandom
DaveRandom

Reputation: 88657

This is a limitation of the Zend engine that I have come across before, particularly when using socket_select()/stream_select(), which both require the "array of resources" arguments to be passed by reference. It would be nice to be able to assign the values of the variables to be passed by reference in one line, but it is not (currently) possible to do it.

I have seen it mentioned before (although right now I can't find where, (It was here) and it may not have been authoritative anyway) that any expression in PHP evaluates to the right-hand side of the expression. By which I mean:

$a = 1;
$b = 2;
echo $a = $b;

This will echo 2, because the expression that was passed the echo statement evaluates the right-hand side of the expression $b, which is 2.

When passing the result of the expression to a function, such as c( $o = b() ); where you are passing the result of $o = b(); to the function c(), it is my understanding (although I could be wrong) that the result of the expression is passed into the function and the function is executed, before a zval is created and assigned to hold $o, behaviour that was designed to reduce memory consumption and speed up internal processing when functions are nested in this way. This means that you have not actually passed the variable by reference, you have simply passed in the value that resulted from b() - the right-hand side of the expression - which cannot be modified by reference since it does not have a variable container.

Indeed, if you turn on E_STRICT messages, you will see the following error:

Strict Standards: Only variables should be passed by reference in ...

...so this behaviour is in fact "by design".

Upvotes: 3

Related Questions