2012-10-19 19 views
7

Po pierwsze, przepraszam za głupie pytanie, ale czytałem artykuł w numerze php.net i nie mogłem zrozumieć, co dokładnie mówi.Przypisanie obiektów w PHP

<?php 
class SimpleClass 
{ 
    // property declaration 
    public $var = 'a default value'; 

    // method declaration 
    public function displayVar() { 
     echo $this->var; 
    } 
} 
?> 



<?php 

$instance = new SimpleClass(); 

$assigned = $instance; 
$reference =& $instance; 

$instance->var = '$assigned will have this value'; 

$instance = null; // $instance and $reference become null 

var_dump($instance); 
var_dump($reference); 
var_dump($assigned); 
?> 

I wyprowadza to:

NULL 
NULL 
object(SimpleClass)#1 (1) { 
    ["var"]=> 
    string(30) "$assigned will have this value" 
} 

$ i $ instancja punkt odniesienia do tego samego miejsca, mam to i rozumiem, dlaczego mamy NULL NULL dla nich.

Ale co z przypisanym $? To także wskazuje miejsce przechowywania instancji $? Dlaczego, gdy używamy $instance->var wpływa na $ przypisane, ale gdy ustawimy $ instance na wartość null, nie ma zmiany dla $ przypisane?

Pomyślałem, że wszystkie trzy zmienne wskazują jedno miejsce w pamięci, ale oczywiście jestem w błędzie. Czy mógłbyś mi wyjaśnić, co dokładnie się dzieje i co jest przypisane $? Dziękuję Ci bardzo!

+0

Masz kod swojej SimpleClass? – user978122

+0

Klasy są odniesieniami w większości przypadków. W PHP nie ma jednak struktury. –

+0

@AlvinWong, IIRC nie jest prawdą przed PHP5 –

Odpowiedz

6

$reference wskazuje na wartość z $instance, która sama jest odniesieniem do obiektu. Więc gdy zmienisz wartość zawartą przez $instance, $reference odzwierciedla tę zmianę.

$assigned, z drugiej strony, jest kopii wartości $instance i niezależnie wskazuje samego obiektu, do którego odnosi się $instance. Tak więc, gdy wartość $instance jest aktualizowana, aby wskazywać na nic (tj. null), nie ma to wpływu na $assigned, ponieważ wciąż wskazuje na obiekt i nie dba o zawartość $instance.

+0

Jeśli przypiszemy jeden obiekt do drugiego, oba będą wskazywały tę samą lokalizację, aż wartość jednego zostanie zmieniona, prawda ? – Dev

+1

No. Zobacz moją odpowiedź. –

4

Ustawienie $instance = null; nie aktualizuje $assigned, ponieważ nie aktualizuje danych w lokalizacji, w której znajdują się $instance punktów. Zamiast tego modyfikuje sam wskaźnik $instance, tak aby wskaźnik nie wskazywał już na te same dane, co $assigned.

+0

Jeśli zastąpisz null dowolną wartością, wynik będzie nadal taki sam – Dev

0

Jak widać w kodzie

$ instance = null; // instancja i $ odwołanie stają się puste

$ instancja stała się teraz równa zeru, ale wcześniej ustawiono $ assign. więc $ assign nie uzyskało wartości pustej. Wartość $ reference odebrała wartość pustą, ponieważ odwołujesz się do niej z wartością = &, która zachowuje wartość instancji $.

2

Obiekt jest oddzielną jednostką w pamięci, która może mieć 1 lub więcej odniesień. Jeśli ma 0, jest to śmieci zebrane.

Zmienna zawierająca obiekt faktycznie wskazuje na (odnosi się do) tego obiektu. Więc kiedy to zrobić:

$var1 = new Object(); 
$var2 = $var1; 

po prostu utworzyć dwie zmienne, wskazując tym samym obiekcie ($ VAR2 kopiuje wartość $ var1, ale ta wartość jest odwołaniem do obiektu).

Jeśli następnie napiszesz, $var1 = null, usuniesz jedno odniesienie, ale $ var2 nadal wskazuje na obiekt.

Operator & faktycznie zwraca referencję do zmiennej za nim, więc kiedy piszesz

$var1 = &var2; 

następnie $ zm1 nie wskazuje na obiekt, do którego $ VAR2 punktów, jak również, ale zm1 $ punkty do samego $ var2. Tak więc gdy zrobisz $ var2 null, $ var1 wskazuje na tę samą wartość null.

+0

jeśli zastąpimy null inną dowolną wartością, wynik będzie taki sam, jeśli zmienimy $ var1 = $ var i $ var, zmienna $ var1 również powinna się zmienić, ponieważ oba wskazują to samo, na wypadek gdybyśmy użyli pewnej wartości zamiast wartości null. – Dev

+0

Nie, nie wskazują na to samo. –

+0

@Dev, Mylisz się co do tego. Po prostu kopiujesz referencje. Odniesienia są rzeczywiście duplikowane, więc masz dwa różne odniesienia wskazujące na jeden obiekt. Poprzez przypisanie wartości NULL do $ var, wystarczy nadpisać jeden odnośnik.Nie obiekt, ani inne odniesienie. – GolezTrol

2

z następującą linię, zastrzegamy sobie lokalizację w pamięci, w których przechowywanie nowego obiektu, a wskaźnik do niego, oznaczony jako $instance:

$instance = new SimpleClass(); 

z następującymi linii tworzymy odniesienie do wskaźnik$instance oznakowanym jako $reference:

$reference =& $instance; 

z następującą linię, zastrzegamy nowy m Emory lokalizacja, oznaczone jako $assigned, różne i Niezależne od tego wyroku, w którym możemy przechowywać kopię wskaźnik (nie sam obiekt) utworzona powyżej:

$assigned = $instance; 

Ustawiając $instance do null, pokochasz zdekonfiguruj tylko wskaźnik do lokalizacji w pamięci, która zawiera rzeczywisty obiekt, a nie sam obiekt. Wszelkie inne odniesienia do niego (na przykład $reference) będą również anulowane.

$assigned jest niezależną kopią wskaźnika (przechowywaną w innym miejscu pamięci), która nadal wskazuje na rzeczywisty obiekt.

Dlatego może być nadal używany w odniesieniu do rzeczywistego obiektu.

Komentarz znaleźć w dokumentacji PHP przychodzi na poparcie tego, co powyżej powiedział:

<?php 
class A { 
    public $foo = 1; 
} 

$a = new A; 
$b = $a; 
$a->foo = 2; 
$a = NULL; 
echo $b->foo."\n"; // 2 

$c = new A; 
$d = &$c; 
$c->foo = 2; 
$c = NULL; 
echo $d->foo."\n"; // Notice: Trying to get property of non-object... 
?> 

Uwaga

Stanowi pewnego rodzaju wyjątkiem, gdy mówimy o zarządzaniu pamięcią. Natomiast kopiowanie zmiennej lub tablicy jest skierowana właśnie przez użycie operatora =, z obiektami będziecie jawnie użyć słowa kluczowego clone, jak podano w dokumentacji PHP:

Wyjątek od zwykłego przypisania przez zachowanie wartości w PHP występuje z obiektami, które są przypisywane przez odniesienie w PHP 5. Obiekty mogą być jawnie kopiowane za pomocą słowa kluczowego klonowania.

+0

To jest mylące. Czy nie przypisano $ instance i $ wskazujących tę samą lokalizację pamięci? Myślę, że przy $ assign = $ instance nie rezerwujemy nowej lokalizacji pamięci dla kopii obiektu, ale wskaźnika wskazującego ten sam obiekt i tę samą lokalizację pamięci, co instancja $. I niczego nie kopiujemy - aby skopiować obiekt, powinniśmy użyć klona. Czy mam rację? – Faery

+0

Przy $ assign = $ instance faktycznie rezerwujemy inną lokalizację pamięci. Nie jest wskaźnikiem: jest to nowy fizyczny adres pamięci, po prostu zmieniony dla wygody użytkownika. –

+0

Dlatego uważam, że wszystkie pozostałe odpowiedzi są mylące (zobacz na przykład komentarze Dev). –

1

Krótka odpowiedź, kiedy utworzyć odwołanie korzystając &, to co się dzieje:

$A ===+ 
     |===> [symbol table entry x] ====> (memory location) 
$B ===+ 

Kiedy robisz normalne zadanie po tym:

$A ===+ 
     |===> [symbol table entry x] ===> (memory location) 
$B ===+         ^
              | 
$C =======> [symbol table entry y] ========+ 

krok LET'S przez kod:

$instance = new SimpleClass(); 

$assigned = $instance; 

Twierdzenie:

$assigned === $instance 

Zarówno $assigned i $instance odniesienie ten sam przypadek SimpleClass.

$reference =& $instance; 

Twierdzenie:

$assigned === $instance === $reference 

Wszystkie zmienne odwołują się do tej samej instancji.

$instance->var = '$assigned will have this value'; 

Twierdzenie:

$assigned === $instance === $reference 

Chociaż właściwością $instance zostanie zmieniona, to nie ma wpływu na referencje.

$instance = null; // $instance and $reference become null 

Ponieważ $reference tylko aliasem w tablicy symboli, to dostaje taką samą wartość jak $instance; licznik odwołań pierwotnej instancji (tj. lokalizacji pamięci) zostaje zmniejszony do 1, zmienna $assigned.

0

To naprawdę proste:

$a = 3; 
$b = $a; 
$c = &$a; 
$a = 0; 

var_dump($a); 
var_dump($b); 
var_dump($c); 

wyjście będzie:

int(0) 
int(3) 
int(0) 

Więc to nie tylko obiekt, ale także przypisanie normalny przydział.