PHP игнорирует передачу по ссылке, если переменная назначена в вызове функции - PullRequest
4 голосов
/ 07 марта 2012

У меня есть две функции

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

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

Затем я пишу следующий код, который, как я ожидаю, должен поместить результат b () в $ o, а затем передать $ o по ссылке на c (), где этоустановить новое значение.все работает нормально:

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

вывод такой, как ожидалось:

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

Но если я попытаюсь присвоить значение $ o при вызове функции следующим образом:

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

Я получаю странный вывод

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

порядок вызовов функций остается тем же, но почему $ o не изменился, несмотря на то, что он был переданпо ссылке?Обязательно ли PHP передает аргумент по значению, если он назначен в вызове функции?Если да, то с какой версии это работало таким образом?Согласно этому комментарию: http://www.php.net/manual/en/functions.arguments.php#71198 в 2006 году он работал по-другому.Моя версия 5.3.6

1 Ответ

3 голосов
/ 07 марта 2012

Это ограничение движка Zend, с которым я сталкивался ранее, особенно при использовании socket_select() / stream_select(), которые оба требуют, чтобы аргументы «массива ресурсов» передавались по ссылке. Было бы неплохо иметь возможность присваивать значения переменных, передаваемых по ссылке, в одной строке, но это (в настоящее время) невозможно сделать.

Я видел упомянутое ранее (, хотя сейчас я не могу найти, где, (это было здесь ), и это, возможно, в любом случае не было авторитетным), что любое выражение в PHP оценивает с правой стороны выражения. Под этим я подразумеваю:

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

Это будет повторять 2, потому что выражение, которое было передано оператору echo, оценивает правую часть выражения $b, которое равно 2.

При передаче результата выражения в функцию, такую ​​как c( $o = b() );, где вы передаете результат $o = b(); в функцию c(), я понимаю (хотя я могу ошибаться), что результат выражения передается в функцию, и функция выполняется, до a zval и назначается для хранения $o, поведение, которое было разработано, чтобы уменьшить потребление памяти и ускорить внутренняя обработка, когда функции вложены таким образом. Это означает, что вы на самом деле не передали переменную по ссылке, вы просто передали значение, полученное из b() - правую часть выражения - которое нельзя изменить по ссылке, поскольку оно не имеет контейнера переменных .

Действительно, если вы включите E_STRICT сообщения, вы увидите следующую ошибку:

Строгие стандарты: только переменные должны передаваться по ссылке в ...

... так что это поведение на самом деле "по замыслу".

...