Le variabili PHP vengono passate per valore o per riferimento?
Le variabili PHP vengono passate per valore o per riferimento?
Risposte:
È 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.'
?>
$str = add_some_extra($str);
se non stessi usando il riferimento, giusto? allora qual è il vero valore aggiunto di quello?
$str
verrebbe assegnata nulla, nel tuo caso.
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.
$y
non è necessario - non c'è nulla function changeValue
che richieda che sia dentro class Y
, quindi si intrecciano due concetti non correlati. Mi sposterei function changeValue
allo 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 type
di $x
- il fatto che entrambi X
e Y
capita di includere un $abc
campo è anche irrilevante per ciò che viene dimostrato
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.
swap
funzione; 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.
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).
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 ...)
$foo
è un puntatore a un oggetto . $foo
viene passato per valore alla funzione changeFoo()
, in quanto changeFoo()
non ha dichiarato il suo parametro con a &
.
È 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
?>
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.
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.
&
.
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
&
.
&
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.
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
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.
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.
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 & 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
Dipende dalla versione, 4 è per valore, 5 è per riferimento.