Le variabili PHP vengono passate per valore o per riferimento?


Risposte:


312

È in base al valore secondo la documentazione di PHP .

Per impostazione predefinita, gli argomenti della funzione vengono passati per valore (in modo che se il valore dell'argomento all'interno della funzione viene modificato, non viene modificato al di fuori della funzione). Per consentire a una funzione di modificare i suoi argomenti, devono essere passati per riferimento.

Per avere un argomento a una funzione sempre passato per riferimento, anteporre una e commerciale ( & ) al nome dell'argomento nella definizione della funzione.

<?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
Ho avuto anche questo dubbio (principiante) - quindi, per essere chiari, sarebbe lo stesso di $str = add_some_extra($str);se non stessi usando il riferimento, giusto? allora qual è il vero valore aggiunto di quello?
Obmerk Kronen,

7
@Obmerk Se non si usasse la e commerciale per indicare come riferimento, non sarebbe equivalente. Notare come la funzione non ha un'istruzione return, quindi $strverrebbe assegnata nulla, nel tuo caso.
The Unknown Dev,

se lo fai in questo modo @ObmerkKronen, dovrai restituire il valore e catturarlo anche attraverso il tuo codice. La variabile iniziale rimarrà la stessa altrimenti.
Nabeel Khan,

Mi chiedo se passare per riferimento abbia qualche vantaggio in termini di prestazioni o no? Sto passando un array di grandi dimensioni e per impostazione predefinita è passa per valore. Quindi, se uso la chiamata per riferimento, ci saranno alcuni vantaggi in termini di prestazioni ??? (mantenendo invariati i valori dell'array durante l'intero processo)
Choxx

4
il vero vantaggio è che puoi manipolare / restituire valori muliple. Puoi anche passare variabili per riferimento e lasciare che la funzione restituisca qualcosa.
Martin Schneider,

65

In PHP, per impostazione predefinita gli oggetti vengono passati come copia di riferimento a un nuovo oggetto.

Vedi questo esempio .............

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

Ora guarda questo ..............

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.

Ora guarda questo ..............

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.

spero che tu possa capire questo.


1
Questo illustra molto bene come funzionano gli handle di oggetti PHP.
Frederik Krautwald,

2
1 ° es, il valore del riferimento dell'obj viene passato alla funzione, le modifiche all'oggetto utilizzando il nuovo riferimento rifletteranno a tutti gli altri riferimenti che puntano allo stesso oggetto. 2 ° ex, di nuovo il VALORE del riferimento dell'obj viene passato alla funzione, la funzione sta cambiando il valore del riferimento per indicare un nuovo obj, il vecchio obj rimane lo stesso. 3 ° ex, il riferimento del valore del riferimento dell'obj viene passato nella funzione, quindi i cambiamenti nella funzione operano sullo stesso oggetto.
s-hunter,

Esempi perfetti ed esattamente quello che pensavo sarebbe successo. Sono un nuovo arrivato in PHP (dallo sfondo Javascript / node.js) e talvolta è difficile capire cosa sta succedendo, ma questo è molto chiaro!
TKoL

Questo esempio è inutilmente complicato. $ynon è necessario - non c'è nulla function changeValueche richieda che sia dentro class Y, quindi si intrecciano due concetti non correlati. Mi sposterei function changeValueallo scopo esterno, appena sopra $x = new X();. Rimuovi tutti i riferimenti a $y. Ora è più facile vedere che i primi due esempi lasciano solo $ x, e il terzo cambia il suo contenuto in new Y(). Il che sarebbe più facile da vedere se hai scaricato il typedi $x- il fatto che entrambi Xe Ycapita di includere un $abccampo è anche irrilevante per ciò che viene dimostrato
ToolmakerSteve

60

Sembra che molte persone siano confuse dal modo in cui gli oggetti vengono passati alle funzioni e dal modo in cui passa per riferimento. Le variabili oggetto vengono comunque passate per valore, è solo il valore che viene passato in PHP5 è un handle di riferimento. Come prova:

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

Uscite:

a, b

Per passare da riferimento mediante possiamo modificare le variabili che sono visti dal chiamante. Che chiaramente il codice sopra non lo fa. Dobbiamo modificare la funzione di scambio in:

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

Uscite:

b, a

per passare per riferimento.


18
Penso che questa prova sia un'errata interpretazione. Sembra che tu stia cercando di scambiare riferimenti. Hai un problema con il modo in cui gli oggetti sono assegnati. Stai riassegnando il riferimento che è immutabile. È il valore a cui punta che può essere modificato dall'interno. La ridefinizione di swap ora sta passando ** x, che consente di cambiare * x. Il problema è pensare che $ x = $ y cambierebbe ciò a cui $ x inizialmente punta.
grantwparks,

9
Questa non è una prova . L'output del primo esempio è esattamente quello che ti aspetteresti se il valore corrente dell'intero oggetto fosse passato alla swapfunzione; in altre parole, se gli oggetti fossero "passati per valore". D'altra parte, è anche esattamente quello che ti aspetteresti se un handle di oggetto fosse passato alla funzione, che in realtà è ciò che accade. Il tuo codice non distingue tra questi due casi.
EML,

31

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

In PHP 5 c'è un nuovo modello a oggetti. La gestione degli oggetti di PHP è stata completamente riscritta, consentendo prestazioni migliori e più funzionalità. Nelle versioni precedenti di PHP, gli oggetti venivano gestiti come tipi primitivi (ad esempio numeri interi e stringhe). Lo svantaggio di questo metodo era che semanticamente l'intero oggetto veniva copiato quando veniva assegnata una variabile o passato come parametro a un metodo. Nel nuovo approccio, gli oggetti sono indicati dall'handle e non dal valore (si può pensare a un handle come identificatore di un oggetto).


25

Le variabili PHP vengono assegnate in base al valore, passate alle funzioni in base al valore e quando contengono / rappresentano oggetti vengono passate per riferimento. Puoi forzare il passaggio delle variabili per riferimento usando un &

Assegnato da esempio valore / riferimento:

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

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

sarebbe uscita

var1: test, var2: test finale, var3: test finale

Passato dall'esempio valore / riferimento:

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

changeThem($var1, $var2);

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

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

produrrebbe:

var1: foo, var2 BAR

Variabili oggetto passate dall'esempio di riferimento:

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

Uscita:

FOO

(l'ultimo esempio potrebbe essere migliore probabilmente ...)


2
Gli "oggetti" non sono valori in PHP5 e non possono essere "passati". Il valore di $fooè un puntatore a un oggetto . $fooviene passato per valore alla funzione changeFoo(), in quanto changeFoo()non ha dichiarato il suo parametro con a &.
newacct

9

È possibile passare una variabile a una funzione per riferimento. Questa funzione sarà in grado di modificare la variabile originale.

È possibile definire il passaggio per riferimento nella definizione della funzione:

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

$result=5;
changeValue($result);

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

6

Lo puoi fare in entrambi i modi.

metti un simbolo '&' davanti e la variabile che stai passando diventa la stessa della sua origine. vale a dire: è possibile passare per riferimento, anziché crearne una copia.

così

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

2
Questo è deprecato e genera un avviso
fijiaaron

5

Le variabili contenenti tipi primitivi vengono passate per valore in PHP5. Le variabili contenenti oggetti vengono passate per riferimento. C'è un articolo abbastanza interessante del Linux Journal del 2006 che menziona questa e altre differenze OO tra 4 e 5.

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


Tutte le variabili vengono passate per valore in PHP se il parametro della funzione non ha &.
newacct

1

Gli oggetti vengono passati per riferimento in PHP 5 e per valore in PHP 4. Le variabili vengono passate per valore per impostazione predefinita!

Leggi qui: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html


Gli "oggetti" non sono valori in PHP5 e non possono essere "passati". Tutte le variabili vengono passate per valore se il parametro della funzione passato a non ha &.
newacct

@newacct non del tutto? Gli oggetti vengono in qualche modo passati per riferimento . Penso di aver osservato che gli oggetti php possono essere modificati dalle funzioni anche quando non sono definiti &davanti ai parametri nella definizione - se fossero passati per valore l'oggetto contenuto nell'ambito che chiamava la funzione con esso come parametro sarebbe non essere influenzato.
Félix Gagnon-Grenier,

3
@ FélixGagnon-Grenier: Ancora una volta, "oggetti" non sono valori e non possono essere "passati". Non puoi avere una "variabile" in PHP5 il cui valore è un "oggetto", puoi avere solo un valore che è un riferimento a un oggetto (cioè un puntatore a un oggetto). Ovviamente puoi passare o assegnare un puntatore a un oggetto in base al valore e modificare l'oggetto a cui punta chiamando un metodo che effettua tale modifica. Ciò non ha nulla a che fare con il passaggio per riferimento. Di che tipo è un valore e se un parametro è pass-by-value / pass-by-reference sono cose indipendenti e ortogonali.
nuovo

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

Gli attributi sono ancora modificabili se non passati per riferimento, quindi fai attenzione.

Produzione:

SwapObjects: b, a SwapValues: a, b


1

Per chiunque lo trovi in ​​futuro, voglio condividere questo gioiello dai documenti PHP, pubblicati da un utente anonimo :

Sembra esserci un po 'di confusione qui. La distinzione tra puntatori e riferimenti non è particolarmente utile. Il comportamento in alcuni degli esempi "completi" già pubblicati può essere spiegato in termini unificanti più semplici. Il codice di Hayley, ad esempio, sta facendo ESATTAMENTE quello che dovresti aspettarti. (Usando> = 5.3)

Primo principio: un puntatore memorizza un indirizzo di memoria per accedere a un oggetto. Ogni volta che viene assegnato un oggetto, viene generato un puntatore. (Non ho ancora approfondito TROPPO nel profondo del motore Zend, ma per quanto posso vedere, questo vale)

Secondo principio e fonte di maggiore confusione: il passaggio di una variabile a una funzione viene eseguito per impostazione predefinita come passaggio di valore, ovvero si sta lavorando con una copia. "Ma gli oggetti vengono passati per riferimento!" Un malinteso comune sia qui che nel mondo Java. Non ho mai detto una copia di COSA. Il passaggio predefinito viene effettuato per valore. Sempre. Ciò che viene copiato e passato, tuttavia, è il puntatore. Quando si utilizza "->", si accederà naturalmente agli stessi interni della variabile originale nella funzione chiamante. Basta usare "=" per giocare solo con le copie.

Terzo principio: "&" imposta automaticamente e permanentemente un altro nome / puntatore variabile sullo stesso indirizzo di memoria di qualcos'altro fino a quando non si disaccoppiano. È corretto usare qui il termine "alias". Pensa a come unire due puntatori all'anca fino a quando forzatamente separati con "unset ()". Questa funzionalità esiste sia nello stesso ambito sia quando un argomento viene passato a una funzione. Spesso l'argomento passato viene chiamato "riferimento", a causa di alcune distinzioni tra "passaggio per valore" e "passaggio per riferimento" che erano più chiare in C e C ++.

Ricorda solo: i puntatori agli oggetti, non agli oggetti stessi, vengono passati alle funzioni. Questi puntatori sono COPIE dell'originale a meno che non si usi "&" nell'elenco dei parametri per passare effettivamente gli originali. Solo quando scavi negli interni di un oggetto gli originali cambieranno.

Ed ecco l'esempio che forniscono:

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

?>

Ho scritto un ampio e dettagliato post sul blog su questo argomento per JavaScript , ma credo che si applichi ugualmente bene a PHP, C ++ e qualsiasi altra lingua in cui le persone sembrano essere confuse su passaggio per valore rispetto a passaggio per riferimento.

Chiaramente, PHP, come C ++, è un linguaggio che supporta il passaggio per riferimento. Per impostazione predefinita, gli oggetti vengono passati per valore. Quando si lavora con variabili che memorizzano oggetti, aiuta a vedere quelle variabili come puntatori (perché è fondamentalmente quello che sono, a livello di assieme). Se si passa un puntatore per valore, è ancora possibile "tracciare" il puntatore e modificare le proprietà dell'oggetto a cui si punta. Quello che non puoi fare è che indichi un oggetto diverso. Solo se dichiari esplicitamente che un parametro viene passato per riferimento, sarai in grado di farlo.


0

In realtà entrambi i metodi sono validi ma dipende dal tuo requisito. I valori di pass per riferimento spesso rallentano lo script. Quindi è meglio passare le variabili in base al valore considerando il tempo di esecuzione. Inoltre, il flusso del codice è più coerente quando si passano le variabili per valore.


0

Utilizzare questo per le funzioni quando si desidera semplicemente modificare la variabile originale e restituirla allo stesso nome di variabile con il nuovo valore assegnato.

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

Dipende dalla versione, 4 è per valore, 5 è per riferimento.


11
Non penso sia vero.
Nick Heiner,

@Karl Seguin, è in parte vero. Prima che l'oggetto PHP5 fosse passato per impostazione predefinita, ma dal 5 erano passati dal gestore, che in pratica può essere trattato come riferimento (con alcune eccezioni) perché possiamo modificare le proprietà dell'oggetto tramite loro php.net/manual/en/language. oop5.references.php .
Adam Faryna,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.