Переменные PHP передаются по значению или по ссылке?

Ответы:

312

Это по стоимости в соответствии с документацией PHP .

По умолчанию аргументы функции передаются по значению (поэтому, если значение аргумента в функции изменяется, оно не изменяется вне функции). Чтобы позволить функции изменять свои аргументы, они должны быть переданы по ссылке.

Чтобы аргумент функции всегда передавался по ссылке, добавьте амперсанд ( & ) к имени аргумента в определении функции.

<?php
function add_some_extra(&$string)
{
    $string .= 'and something extra.';
}

$str = 'This is a string, ';
add_some_extra($str);
echo $str;    // outputs 'This is a string, and something extra.'
?>
Майкл Стум
источник
4
У меня также было это сомнение (новичок) - так что для ясности, это было бы так же, как $str = add_some_extra($str);если бы я не использовал ссылку, верно? тогда какова реальная добавленная стоимость этого?
Обмерк Кронен
7
@Obmerk Если вы не используете амперсанд для обозначения по ссылке, это не будет эквивалентно. Обратите внимание, что функция не имеет оператора возврата, поэтому $strв вашем случае ей будет присвоен ноль.
Неизвестный разработчик
если вы сделаете это таким образом @ObmerkKronen, то вам придется вернуть значение и перехватить его через ваш код. В противном случае исходная переменная останется прежней.
Набиль Хан
Мне интересно, если передача по ссылке имеет некоторые преимущества в производительности или нет? Я передаю большой массив и по умолчанию он передается по значению. Итак, если я использую вызов по ссылке, будет ли какая-то полезная производительность ??? (сохранение значений массива в течение всего процесса)
Choxx
4
реальная выгода в том, что вы можете манипулировать / возвращать несколько значений. Вы также можете передавать переменные по ссылке и при этом позволить функции возвращать что-то.
Мартин Шнайдер
65

В PHP по умолчанию объекты передаются как ссылочная копия в новый объект.

Посмотрите этот пример .............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue($obj)
  {
   $obj->abc = 30;
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 30

Теперь посмотри на это ..............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue($obj)
  {
    $obj = new Y();
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 10 not 20 same as java does.

Теперь посмотри на это ..............

class X {
  var $abc = 10; 
}

class Y {

  var $abc = 20; 
  function changeValue(&$obj)
  {
    $obj = new Y();
  }
}

$x = new X();
$y = new Y();

echo $x->abc; //outputs 10
$y->changeValue($x);
echo $x->abc; //outputs 20 not possible in java.

Я надеюсь, что вы можете понять это.

Hardik
источник
1
Это очень хорошо иллюстрирует, как работает PHP-объект.
Фредерик Краутвальд
2
1-й пример, значение ссылки на объект передается в функцию, изменения в объекте с использованием новой ссылки будут отражать все остальные ссылки, указывающие на тот же объект. 2-й пример, снова ЗНАЧЕНИЕ ссылки на объект передается в функцию, функция изменяет значение ссылки, чтобы указать на новый объект, старый объект остается неизменным. 3-й пример, ссылка на значение ссылки на объект передается в функцию, таким образом, изменения в функции действуют на тот же объект.
S-Hunter
Прекрасные примеры и именно то, что я думал, произойдет. Я новичок в PHP (из фона Javascript / node.js), и иногда трудно понять, что происходит, но это очень ясно!
TKoL
Этот пример излишне сложен. $yв этом нет необходимости - нет ничего, function changeValueчто требовало бы, чтобы оно было внутри class Y, чтобы объединить два не связанных между собой понятия. Я бы переместился function changeValueво внешнюю сферу, чуть выше $x = new X();. Удалить все ссылки на $y. Теперь легче увидеть, что первые два примера оставляют $ x в покое, а третий меняет свое содержимое на new Y(). Какой бы легче увидеть , если вы выбросили typeиз $x- за того , что , как Xи Yслучается, включают в себя $abcполе также не имеет отношения к тому , что показано
ToolmakerSteve
60

Кажется, многие люди смущаются тем, как объекты передаются в функции и что означает передача по ссылке. Переменные объекта по-прежнему передаются по значению, просто значение, которое передается в PHP5, является дескриптором ссылки. Как доказательство:

<?php
class Holder {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function getValue() {
        return $this->value;
    }
}

function swap($x, $y) {
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);

echo $a->getValue() . ", " . $b->getValue() . "\n";

Выходы:

a, b

Для передачи по ссылке мы можем изменить переменные, которые видит вызывающий. Который явно код выше не делает. Нам нужно изменить функцию подкачки на:

<?php
function swap(&$x, &$y) {
    $tmp = $x;
    $x = $y;
    $y = $tmp;
}

$a = new Holder('a');
$b = new Holder('b');
swap($a, $b);

echo $a->getValue() . ", " . $b->getValue() . "\n";

Выходы:

b, a

чтобы перейти по ссылке.

Grom
источник
18
Я думаю, что это доказательство является неверным толкованием. Похоже, вы пытались обменяться ссылками. У вас проблема с назначением объектов. Вы переназначаете ссылку, которая является неизменной. Это значение, на которое оно указывает, может быть изменено изнутри. Переопределение swap теперь проходит ** x, что позволяет вам изменить * x. Проблема в том, что мы думаем, что $ x = $ y изменит то, на что изначально указывает $ x.
grantwparks
9
Это не доказательство . Результат первого примера - именно то, что вы ожидаете, если текущее значение всего объекта будет передано swapфункции; другими словами, если объекты были «переданы по значению». С другой стороны, это именно то, что вы ожидаете, если дескриптор объекта будет передан функции, что на самом деле и происходит. Ваш код не различает эти два случая.
EML
31

http://www.php.net/manual/en/migration5.oop.php

В PHP 5 появилась новая объектная модель. Обработка объектов в PHP была полностью переписана, что позволило повысить производительность и расширить возможности. В предыдущих версиях PHP объекты обрабатывались как примитивные типы (например, целые числа и строки). Недостатком этого метода было то, что семантически весь объект копировался при присвоении переменной или передавался в качестве параметра методу. В новом подходе на объекты ссылаются по дескриптору, а не по значению (можно рассматривать дескриптор как идентификатор объекта).

Карл Сегуин
источник
25

Переменные PHP присваиваются по значению, передаются в функции по значению, а когда содержат / представляют объекты, передаются по ссылке. Вы можете принудительно передать переменные по ссылке, используя &

Назначено по значению / справочному примеру:

$var1 = "test";
$var2 = $var1;
$var2 = "new test";
$var3 = &$var2;
$var3 = "final test";

print ("var1: $var1, var2: $var2, var3: $var3);

будет выводить

var1: тест, var2: финальный тест, var3: финальный тест

Передано по стоимости / справочный экзамен:

$var1 = "foo";
$var2 = "bar";

changeThem($var1, $var2);

print "var1: $var1, var2: $var2";

function changeThem($var1, &$var2){
    $var1 = "FOO";
    $var2 = "BAR";
}

будет выводить:

var1: foo, var2 BAR

Переменные объекта, переданные по ссылке

class Foo{
    public $var1;

    function __construct(){
        $this->var1 = "foo";
    }

    public function printFoo(){
        print $this->var1;
    }
}


$foo = new Foo();

changeFoo($foo);

$foo->printFoo();

function changeFoo($foo){
    $foo->var1 = "FOO";
}

Будет вывод:

FOO

(последний пример мог бы быть лучше ...)

cmcculloh
источник
2
«Объекты» не являются значениями в PHP5 и не могут быть «переданы». Значение $fooявляется указателем на объект . $fooбудет передаваться по значению функции changeFoo(), а changeFoo()не объявить его параметр с &.
newacct
9

Вы можете передать переменную в функцию по ссылке. Эта функция сможет изменять исходную переменную.

Вы можете определить переход по ссылке в определении функции:

<?php
function changeValue(&$var)
{
    $var++;
}

$result=5;
changeValue($result);

echo $result; // $result is 6 here
?>
Mahsin
источник
6

Вы можете сделать это в любом случае.

поместите символ «&» перед собой, и переменная, которую вы передаете, становится такой же, как и ее источник. То есть: вы можете передать по ссылке, а не сделать его копию.

так

    $fred = 5;
    $larry = & $fred;
    $larry = 8;
    echo $fred;//this will output 8, as larry and fred are now the same reference.
Bingy
источник
2
Это устарело и
выдает
5

Переменные, содержащие примитивные типы, передаются по значению в PHP5. Переменные, содержащие объекты, передаются по ссылке. В Linux Journal от 2006 года есть довольно интересная статья, в которой упоминается это и другие различия между 4 и 5.

http://www.linuxjournal.com/article/9170

Polsonby
источник
Все переменные передаются по значению в PHP, если параметр функции не имеет &.
newacct
1

Объекты передаются по ссылке в PHP 5 и по значению в PHP 4. Переменные по умолчанию передаются по значению!

Читайте здесь: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html

Miha
источник
«Объекты» не являются значениями в PHP5 и не могут быть «переданы». Все переменные передаются по значению, если параметр передаваемой функции не имеет &.
newacct
@newacct не совсем? Объекты несколько передаются по ссылке . Я думаю, что я заметил, что объекты php могут быть изменены функциями, даже если они не определены &перед параметрами в определении - если они были переданы по значению, объект, содержащийся в области видимости, который вызвал функцию с этим параметром, не быть затронутым.
Феликс Ганьон-Гренье
3
@ FélixGagnon-Grenier: опять же, «объекты» не являются значениями и не могут быть «переданы». Вы не можете иметь «переменную» в PHP5, значение которой является «объектом», вы можете иметь только значение, которое является ссылкой на объект (то есть указатель на объект). Конечно, вы можете передать или назначить указатель на объект по значению и изменить объект, на который он указывает, вызвав метод, который выполняет такое изменение. Это не имеет ничего общего с передачей по ссылке. Тип значения и то, является ли параметр передачей по значению / передачей по ссылке, являются независимыми и ортогональными вещами.
newacct
1
class Holder
{
    private $value;

    public function __construct( $value )
    {
        $this->value = $value;
    }

    public function getValue()
    {
        return $this->value;
    }

    public function setValue( $value )
    {
        return $this->value = $value;
    }
}

class Swap
{       
    public function SwapObjects( Holder $x, Holder $y )
    {
        $tmp = $x;

        $x = $y;

        $y = $tmp;
    }

    public function SwapValues( Holder $x, Holder $y )
    {
        $tmp = $x->getValue();

        $x->setValue($y->getValue());

        $y->setValue($tmp);
    }
}


$a1 = new Holder('a');

$b1 = new Holder('b');



$a2 = new Holder('a');

$b2 = new Holder('b');


Swap::SwapValues($a1, $b1);

Swap::SwapObjects($a2, $b2);



echo 'SwapValues: ' . $a2->getValue() . ", " . $b2->getValue() . "<br>";

echo 'SwapObjects: ' . $a1->getValue() . ", " . $b1->getValue() . "<br>";

Атрибуты по-прежнему можно изменять, если они не передаются по ссылке, поэтому будьте осторожны.

Вывод:

SwapObjects: b, a SwapValues: a, b

Рикардо Сарачино
источник
1

Для тех, кто сталкивается с этим в будущем, я хочу поделиться этим драгоценным камнем из документов PHP, опубликованных анонимным пользователем :

Кажется, здесь есть некоторая путаница. Различие между указателями и ссылками не особенно полезно. Поведение в некоторых уже опубликованных «всеобъемлющих» примерах можно объяснить более простыми объединяющими терминами. Например, код Хейли делает именно то, что и следовало ожидать. (Используя> = 5.3)

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

2-й принцип и источник наибольшей путаницы: передача переменной в функцию выполняется по умолчанию как передача значения, т. Е. Вы работаете с копией. «Но объекты передаются по ссылке!» Распространенное заблуждение как здесь, так и в мире Java. Я никогда не говорил копию ЧТО. Передача по умолчанию выполняется по значению. Всегда. То, что копируется и передается, однако, является указателем. Используя «->», вы, конечно, будете получать доступ к тем же внутренним элементам, что и исходная переменная в функции вызывающей стороны. Просто используя «=» будет играть только с копиями.

Третий принцип: «&» автоматически и навсегда устанавливает другое имя переменной / указатель на тот же адрес памяти, что и другие, до тех пор, пока вы не отделите их. Здесь правильно использовать термин «псевдоним». Думайте об этом как о соединении двух указателей на бедре, пока они не будут принудительно разделены с помощью "unset ()". Эта функциональность существует как в одной и той же области видимости, так и при передаче аргумента в функцию. Часто передаваемый аргумент называется «ссылкой» из-за определенных различий между «передачей по значению» и «передачей по ссылке», которые были более понятными в C и C ++.

Просто помните: указатели на объекты, а не сами объекты, передаются функциям. Эти указатели являются КОПИЯМИ оригинала, если вы не используете «&» в своем списке параметров для фактической передачи оригиналов. Только когда вы копаете внутренности объекта, оригиналы изменятся.

И вот пример, который они предоставляют:

<?php

//The two are meant to be the same
$a = "Clark Kent"; //a==Clark Kent
$b = &$a; //The two will now share the same fate.

$b="Superman"; // $a=="Superman" too.
echo $a;
echo $a="Clark Kent"; // $b=="Clark Kent" too.
unset($b); // $b divorced from $a
$b="Bizarro";
echo $a; // $a=="Clark Kent" still, since $b is a free agent pointer now.

//The two are NOT meant to be the same.
$c="King";
$d="Pretender to the Throne";
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByValue($c, $d);
echo $c."\n"; // $c=="King"
echo $d."\n"; // $d=="Pretender to the Throne"
swapByRef($c, $d);
echo $c."\n"; // $c=="Pretender to the Throne"
echo $d."\n"; // $d=="King"

function swapByValue($x, $y){
$temp=$x;
$x=$y;
$y=$temp;
//All this beautiful work will disappear
//because it was done on COPIES of pointers.
//The originals pointers still point as they did.
}

function swapByRef(&$x, &$y){
$temp=$x;
$x=$y;
$y=$temp;
//Note the parameter list: now we switched 'em REAL good.
}

?>

Я написал обширный, подробный пост в блоге на эту тему для JavaScript , но я полагаю, что он одинаково хорошо применим к PHP, C ++ и любому другому языку, где люди, похоже, не понимают передачу по значению по сравнению с передачей по ссылке.

Очевидно, что PHP, как и C ++, является языком, который поддерживает передачу по ссылке. По умолчанию объекты передаются по значению. При работе с переменными, которые хранят объекты, это помогает видеть эти переменные как указатели (потому что это на самом деле то, чем они являются на уровне сборки). Если вы передаете указатель по значению, вы все равно можете «проследить» указатель и изменить свойства объекта, на который указывает указатель. То, что вы не можете сделать, это указать на другой объект. Только если вы явно объявите параметр как переданный по ссылке, вы сможете сделать это.

AleksandrH
источник
0

На самом деле оба метода действительны, но это зависит от ваших требований. Передача значений по ссылке часто замедляет выполнение сценария. Поэтому лучше передавать переменные по значению, учитывая время выполнения. Кроме того, поток кода более согласован, когда вы передаете переменные по значению.

Atif
источник
0

Используйте это для функций, когда вы хотите просто изменить исходную переменную и вернуть ее снова к тому же имени переменной с назначенным ей новым значением.

function add(&$var){ // The &amp; is before the argument $var
   $var++;
}
$a = 1;
$b = 10;
add($a);
echo "a is $a,";
add($b);
echo " a is $a, and b is $b"; // Note: $a and $b are NOT referenced
PPL
источник
-7

Зависит от версии, 4 по значению, 5 по ссылке.

Карл Сегуин
источник
11
Я не думаю, что это правда.
Ник Хейнер
@ Карл Сегин, это отчасти правда. До PHP5 объекты по умолчанию передавались по значению, но с 5 они передаются обработчиком, который на практике может рассматриваться как ссылка (с некоторыми исключениями), потому что мы можем изменять свойства объекта через них php.net/manual/en/language. oop5.references.php .
Адам Фарина