Podręcznik PHP
Poprzedni | Rozdział 13. Klasy i Obiekty | Następny

# Referencje wewnątrz konstruktora

Tworzenie referencji wewnątrz konstruktora może prowadzić do dziwnych efektów. Ten rozdział ma pomóc w unikaniu takich problemów.

`class Foo { function Foo($nazwa) { // stworz referencje wewnatrz globalnej tablicy $globalref global $globalref; $globalref[] = &$this; // ustaw nazwę na przekazaną wartość $this->ustawNazwe($nazwa); // i wyświetl ją $this->wyswietlNazwe(); } function wyswietlNazwe() { echo "<br>",$this->nazwa; } function ustawNazwe($nazwa) { $this->nazwa = $nazwa; } }`

Sprawdźmy, czy jest jakaś różnica pomiędzy `$bar1`, który jest tworzony przy pomocy operatora przypisania `=`, a `$bar2`, który został stworzony używając operatora referencji `=&`...

`$bar1 = new Foo('ustawione w konstruktorze'); $bar1->wyswietlNazwe(); $globalref[0]->wyswietlNazwe(); /* wyjście: ustawione w konstruktorze ustawione w konstruktorze ustawione w konstruktorze */ $bar2 =& new Foo('ustawione w konstruktorze'); $bar2->wyswietlNazwe(); $globalref[1]->wyswietlNazwe(); /* wyjście: ustawione w konstruktorze ustawione w konstruktorze ustawione w konstruktorze */`

Wydaje się, że nie ma żadnej różnicy, ale na prawdę jest jedna, i to bardzo istotna: `$bar1` i `$globalref[0]` NIE są referencjami, NIE są tą samą zmienna. Dzieje się tak, ponieważ "new" nie zwraca domyślnie referencji, ale kopię.

> Notatka: Zwracanie kopii zamiast referencji nie powoduje utraty wydajności (od PHP 4 używane jest zliczanie referencji). Jednakże zazwyczaj lepiej jest pracować poprostu z kopiami zamiast referencji, poniewać tworzenie referencji zabiera trochę czasu, podczas gdy tworzenie kopii obiektów teoretycznie w ogóle nie zabiera czasu (chyba że któraś z tych zmiennych jest dużą tablicą lub obiektem i jedno z nich ulega zmianie, po czym tej samej zmianie ulegają pozostałe zmienne; wtedy lepiej jest użyć referencji do zmieniania ich równolegle).

Aby udowodnić to, co zostało zapisane powyżej, przyjrzyjmy się poniższemu programowi.

`// teraz zmienimy nazwę. czego się spodziewasz? // możesz się spodziewać, że i $bar1 i $globalref[0] zmienią swoje nazwy... $bar1->ustawNazwe('ustawiona z zewnątrz'); // jak napisano powyżej, nic takiego się nie stanie $bar1->wyswietlNazwe(); $globalref[0]->wyswietlNazwe(); /* wyjście: ustawiona z zewnątrz ustawiona w konstruktorze */ // zobaczmy co się dzieje z $bar2 i $globalref[1] $bar2->ustawNazwe('ustawiona z zewnątrz'); // na szczęście ta zmienna nie zachowuje się jak ta z poprzedniego przypadku // są to te same zmienne, z więc $bar2->nazwa i $globalref[1]->nazwa są także // tymi samymi zmiennymi $bar2->wyswietlNazwe(); $globalref[1]->wyswietlNazwe(); /* wyjście: ustawiona z zewnątrz ustawiona z zewnątrz */`

Ustatni przykład. Postaraj się go zrozumieć/

`class A { function A($i) { $this->wartosc = $i; // domyśl się dlaczego nie potrzebujemy tutaj referencji $this->b = new B($this); } function stworzRef() { $this->c = new B($this); } function wyswietlWartosc() { echo "<br>","klasa ",get_class($this),': ',$this->value; } } class B { function B(&$a) { $this->a = &$a; } function wyswietlWartosc() { echo "<br>","klasa ",get_class($this),': ',$this->a->value; } } // spróbuj zrozumieć dlaczego użycie tu prostego kopiowania może powodować // nieporządany efekt w linii uznaczonej znaczkiem '*' $a =& new A(10); $a->stworzRef(); $a->wyswietlWartosc(); $a->b->wyswietlWartosc(); $a->c->wyswietlWartosc(); $a->value = 11; $a->wyswietlWartosc(); $a->b->wyswietlWartosc(); // * $a->c->wyswietlWartosc(); /* wyjście: klasa A: 10 klasa B: 10 klasa B: 10 klasa A: 11 klasa B: 11 klasa B: 11 */`

Poprzedni | Spis treści | Następny
Magiczne funkcje `__sleep` i `__wakeup` | Początek rozdziału | References Explained