Czy zmienne PHP są przekazywane przez wartość czy przez referencję?
Czy zmienne PHP są przekazywane przez wartość czy przez referencję?
Odpowiedzi:
Jest pod względem wartości, zgodnie z Dokumentacją PHP .
Domyślnie argumenty funkcji są przekazywane przez wartość (tak, że jeśli wartość argumentu w funkcji zostanie zmieniona, nie zostanie zmieniona poza funkcją). Aby umożliwić funkcji modyfikowanie jej argumentów, muszą zostać przekazane przez odwołanie.
Aby argument funkcji był zawsze przekazywany przez odwołanie, wstaw znak ampersand ( & ) do nazwy argumentu w definicji funkcji.
<?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);
gdybym nie używał referencji, prawda? jaka jest zatem prawdziwa wartość dodana tego?
$str
w twoim przypadku zostanie przypisana null.
W PHP obiekty są domyślnie przekazywane jako kopia referencyjna do nowego obiektu.
Zobacz ten przykład .............
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
Teraz zobacz to ..............
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.
Teraz zobacz to ..............
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.
mam nadzieję, że to zrozumiesz.
$y
nie jest potrzebne - nie ma w function changeValue
tym nic, co wymagałoby, aby było w środku class Y
, więc splata się dwie niezwiązane ze sobą koncepcje. Chciałbym przejść function changeValue
do zakresu zewnętrznego, tuż powyżej $x = new X();
. Usuń wszystkie odniesienia do $y
. Teraz łatwiej zauważyć, że pierwsze dwa przykłady pozostawiają $ x w spokoju, a trzeci zmienia jego zawartość na new Y()
. Co byłoby łatwiej sprawdzić, czy wyrzucił type
z $x
- fakt, że zarówno X
i Y
stało się zawierać $abc
pole ma również znaczenia, co zostanie wykazane
Wygląda na to, że wielu ludzi jest zdezorientowanych sposobem, w jaki obiekty są przekazywane do funkcji i co przekazuje się przez odniesienie. Zmienne obiektowe są nadal przekazywane przez wartość, tylko wartość przekazywana w PHP5 jest uchwytem referencyjnym. Jako dowód:
<?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";
Wyjścia:
a, b
Aby przekazać przez referencję , możemy zmodyfikować zmienne widoczne dla dzwoniącego. Które wyraźnie powyższy kod nie działa. Musimy zmienić funkcję wymiany na:
<?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";
Wyjścia:
b, a
w celu przekazania przez odniesienie.
swap
funkcji; innymi słowy, jeśli obiekty zostały „przekazane przez wartość”. Z drugiej strony jest to dokładnie to, czego można oczekiwać, jeśli uchwyt obiektu zostałby przekazany do funkcji, co faktycznie się dzieje. Twój kod nie rozróżnia tych dwóch przypadków.
http://www.php.net/manual/en/migration5.oop.php
W PHP 5 istnieje nowy model obiektowy. Obsługa obiektów przez PHP została całkowicie przepisana, co pozwala na lepszą wydajność i więcej funkcji. W poprzednich wersjach PHP obiekty były traktowane jak typy pierwotne (na przykład liczby całkowite i łańcuchy). Wadą tej metody było to, że semantycznie cały obiekt został skopiowany, gdy zmienna została przypisana lub przekazana jako parametr do metody. W nowym podejściu do obiektów odwołuje się uchwyt, a nie wartość (uchwyt można traktować jako identyfikator obiektu).
Zmienne PHP są przypisywane przez wartość, przekazywane do funkcji przez wartość, a gdy zawierają / reprezentują obiekty są przekazywane przez odwołanie. Możesz wymusić przekazywanie zmiennych przez referencję za pomocą &
Przypisany przez przykład wartości / odniesienia:
$var1 = "test";
$var2 = $var1;
$var2 = "new test";
$var3 = &$var2;
$var3 = "final test";
print ("var1: $var1, var2: $var2, var3: $var3);
wyszedłby
var1: test, var2: test końcowy, var3: test końcowy
Przekazywane przez przykład wartości / odniesienia:
$var1 = "foo";
$var2 = "bar";
changeThem($var1, $var2);
print "var1: $var1, var2: $var2";
function changeThem($var1, &$var2){
$var1 = "FOO";
$var2 = "BAR";
}
wyprowadziłby:
var1: foo, var2 BAR
Zmienne obiektowe przekazywane przez przykład odniesienia:
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";
}
Wyprowadziłby:
BLA
(ten ostatni przykład może być lepszy prawdopodobnie ...)
$foo
jest wskaźnikiem do obiektu . $foo
jest przekazywany przez wartość do funkcji changeFoo()
, ponieważ changeFoo()
nie zadeklarował swojego parametru za pomocą a &
.
Możesz przekazać zmienną do funkcji przez odwołanie. Ta funkcja będzie mogła modyfikować oryginalną zmienną.
Możesz zdefiniować przejście przez odniesienie w definicji funkcji:
<?php
function changeValue(&$var)
{
$var++;
}
$result=5;
changeValue($result);
echo $result; // $result is 6 here
?>
Możesz to zrobić w obie strony.
umieść symbol „&” z przodu, a przekazywana zmienna stanie się jednym i tym samym co jej pochodzenie. tzn .: możesz przekazać referencję zamiast robić jej kopię.
więc
$fred = 5;
$larry = & $fred;
$larry = 8;
echo $fred;//this will output 8, as larry and fred are now the same reference.
Zmienne zawierające pierwotne typy są przekazywane przez wartość w PHP5. Zmienne zawierające obiekty są przekazywane przez odniesienie. Jest dość interesujący artykuł z Linux Journal z 2006 roku, który wspomina o tej i innych różnicach OO między 4 a 5.
&
.
Obiekty są przekazywane przez odniesienie w PHP 5 i przez wartość w PHP 4. Zmienne są domyślnie przekazywane przez wartość!
Przeczytaj tutaj: http://www.webeks.net/programming/php/ampersand-operator-used-for-assigning-reference.html
&
.
&
przed parametrami w definicji - gdyby zostały przekazane przez wartość, obiekt zawarty w zakresie, który wywołał funkcję z tym parametrem nie ma to wpływu.
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>";
Atrybuty można modyfikować, jeśli nie zostaną przekazane przez odniesienie, więc uważaj.
Wynik:
SwapObjects: b, a SwapValues: a, b
Dla każdego, kto spotka się z tym w przyszłości, chcę udostępnić ten klejnot z dokumentów PHP, opublikowanych przez anonimowego użytkownika :
Wydaje się, że jest tu trochę zamieszania. Rozróżnienie wskaźników i odniesień nie jest szczególnie pomocne. Zachowanie w niektórych opublikowanych już „kompleksowych” przykładach można wyjaśnić w prostszy sposób ujednolicający. Na przykład kod Hayley robi DOKŁADNIE to, czego należy się spodziewać. (Używanie> = 5,3)
Pierwsza zasada: Wskaźnik przechowuje adres pamięci w celu uzyskania dostępu do obiektu. Za każdym razem, gdy obiekt jest przypisany, generowany jest wskaźnik. (Nie zagłębiłem się zbyt głęboko w silnik Zend, ale o ile widzę, dotyczy to)
Druga zasada i źródło największego zamieszania: Przekazywanie zmiennej do funkcji jest domyślnie wykonywane jako przekazywanie wartości, tzn. Pracujesz z kopią. „Ale obiekty są przekazywane przez odniesienie!” Powszechne nieporozumienie zarówno tutaj, jak i w świecie Java. Nigdy nie powiedziałem kopii CO. Domyślne przekazywanie odbywa się według wartości. Zawsze. CO jest jednak kopiowane i przekazywane jest wskaźnikiem. Korzystając z „->”, oczywiście uzyskujesz dostęp do tych samych elementów wewnętrznych, co oryginalna zmienna w funkcji wywołującej. Wystarczy użyć „=”, aby odtwarzać tylko kopie.
Trzecia zasada: „&” automatycznie i na stałe ustawia inną nazwę / wskaźnik zmiennej na ten sam adres pamięci, co coś innego, dopóki ich nie oddzielisz. Prawidłowe jest użycie tutaj terminu „alias”. Pomyśl o tym jako o połączeniu dwóch wskaźników na biodrze, aż do wymuszonego oddzielenia przez „unset ()”. Ta funkcjonalność istnieje zarówno w tym samym zakresie, jak i po przekazaniu argumentu do funkcji. Często przekazywany argument nazywany jest „referencją” z powodu pewnych rozróżnień między „przekazywaniem przez wartość” i „przekazywaniem przez referencję”, które były wyraźniejsze w C i C ++.
Pamiętaj tylko: wskaźniki do obiektów, a nie same obiekty, są przekazywane do funkcji. Wskaźniki te są KOPIAMI oryginału, chyba że użyjesz „&” na liście parametrów, aby faktycznie przekazać oryginały. Dopiero po wbiciu się w wnętrze obiektu oryginały się zmienią.
Oto przykład, który podają:
<?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.
}
?>
Napisałem obszerny, szczegółowy post na blogu na ten temat dla JavaScript , ale uważam, że ma on zastosowanie równie dobrze do PHP, C ++ i każdego innego języka, w którym ludzie wydają się być zdezorientowani w kwestii przekazywania według wartości i przekazywania przez odniesienie.
Oczywiście PHP, podobnie jak C ++, jest językiem, który obsługuje przekazywanie przez referencję. Domyślnie obiekty są przekazywane według wartości. Podczas pracy ze zmiennymi, które przechowują obiekty, pomaga postrzegać te zmienne jako wskaźniki (ponieważ jest to zasadniczo to, co one są, na poziomie zespołu). Jeśli przekażesz wskaźnik według wartości, nadal możesz „śledzić” wskaźnik i modyfikować właściwości wskazywanego obiektu. To, czego nie możesz zrobić, to wskazanie innego obiektu. Tylko jeśli wyraźnie zadeklarujesz parametr jako przekazany przez referencję, będziesz w stanie to zrobić.
Właściwie obie metody są poprawne, ale zależy to od twoich wymagań. Wartości referencyjne często powodują spowolnienie skryptu. Dlatego lepiej jest przekazywać zmienne według wartości, biorąc pod uwagę czas wykonania. Również przepływ kodu jest bardziej spójny, gdy zmienne są przekazywane według wartości.
Użyj tego dla funkcji, gdy chcesz po prostu zmienić oryginalną zmienną i przywrócić ją ponownie do tej samej nazwy zmiennej z przypisaną nową wartością.
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
Zależy od wersji, 4 to wartość, 5 to wartość referencyjna.