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).
// 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 |