Blog literacki, portal erotyczny - seks i humor nie z tej ziemi
Referencje wewnątrz konstruktoraPodręcznik PHPPoprzedniRozdział 13. Klasy i ObiektyNastępnyReferencje 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
*/
PoprzedniSpis treściNastępnyMagiczne funkcje __sleep i __wakeupPoczątek rozdziałuReferences Explained