Чи передаються змінні PHP за значенням або за посиланням?


Відповіді:


310

Це за значенням відповідно до документації 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в вашому випадку буде присвоєно нуль.
Невідомий Dev

якщо ви зробите це так @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.

сподіваюся, ви можете це зрозуміти.


1
Це дуже добре ілюструє, як працює об'єкт PHP.
Фредерік Краутвальд

2
По-перше, значення посилання на obj передається функції, зміни на obj з використанням нового посилання відображатимуться до всіх інших посилань, що вказують на той самий obj. 2-е колишнє, ЗНАЙДАЄТЬСЯ ЗНАЧЕННЯ посилання obj передається функції, функція змінює значення посилання, щоб вказувати на новий obj, старий obj залишається таким же. 3-е пр., Посилання на значення посилання на obj передається у функцію, таким чином, зміни функції функціонують на тому самому obj.
s-мисливець

Ідеальні приклади і саме те, що я думав, що станеться. Я новачок у 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

Для передачі посилання означає, що ми можемо змінювати змінні, які бачать абонент. Який чітко код вище не робить. Нам потрібно змінити функцію swap на:

<?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

для того, щоб пройти посилання.


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";
}

Виведе:

ФОО

(останній приклад міг би бути кращим, напевно ...)


2
"Об'єкти" не є значеннями в PHP5 і не можуть бути "передані". Значення $foo- вказівник на об’єкт . $fooбуде передаватися за значенням функції changeFoo(), а changeFoo()не оголосив його параметр з &.
newacct

9

Ви можете передати змінну функції посиланням. Ця функція зможе змінити вихідну змінну.

Ви можете визначити уривок за посиланням у визначенні функції:

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

$result=5;
changeValue($result);

echo $result; // $result is 6 here
?>

6

Ви можете це зробити будь-яким способом.

поставте символ "&" попереду, і змінна, яку ви проходите, стає однією і тією ж, що і її походження. тобто: ви можете пройти посилання, а не зробити його копію.

так

    $fred = 5;
    $larry = & $fred;
    $larry = 8;
    echo $fred;//this will output 8, as larry and fred are now the same reference.

2
Це застаріло і створює попередження
fijiaaron

5

Змінні, що містять примітивні типи, передаються за значенням у PHP5. Змінні, що містять об'єкти, передаються за посиланням. Існує досить цікава стаття з Linux Journal від 2006 року, в якій згадується це та інші відмінності OO між 4 та 5.

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


Усі змінні передаються за значенням у PHP, якщо параметр функції не має &.
newacct

1

Об'єкти передаються за посиланням у PHP 5 та за значенням у PHP 4. Змінні передаються за значенням за замовчуванням!

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


"Об'єкти" не є значеннями в 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, але, наскільки я бачу, це стосується)

Другий принцип і джерело найбільш непорозумінь: Передача змінної функції виконується за замовчуванням як пропуск значення, тобто ви працюєте з копією. "Але об'єкти передаються за посиланням!" Поширена помилка як тут, так і в світі 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 ++, є мовою, яка підтримує передачу посилання. За замовчуванням об'єкти передаються за значенням. Працюючи зі змінними, що зберігають об’єкти, це допомагає розглянути ці змінні як покажчики (адже це принципово те, що вони є, на рівні складання). Якщо ви передаєте вказівник за значенням, ви все одно можете "простежити" вказівник та змінити властивості об'єкта, на який вказують. Що ви не можете зробити, це вказати на інший об’єкт. Тільки якщо ви явно оголосите параметр як переданий посиланням, ви зможете це зробити.


0

Насправді обидва способи дійсні, але це залежить від вашої вимоги. Значення балів за посиланням часто робить ваш сценарій повільним. Тож краще передавати змінні за значенням, враховуючи час виконання. Також потік коду є більш послідовним, коли ви передаєте змінні за значенням.


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

-7

Залежить від версії, 4 - за значенням, 5 - за посиланням.


11
Я не думаю, що це правда.
Нік Хайнер

@Karl Seguin, частково це правда. Перед тим як об'єкт PHP5 за замовчуванням передавались за значенням, але, оскільки 5 передаються обробником, що на практиці може трактуватися як посилання (за деякими винятками), оскільки ми можемо змінювати властивості об'єкта через них php.net/manual/en/language. oop5.references.php .
Адам Фарина
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.