Referenciák a konstruktorban
Referenciák képzése kontruktorokban problémás helyzetekhez vezethet. Ez a leírás segít a bajok elkerülésében.
<?php
class Ize {
function Ize($nev) {
// egy referencia létrehozása a globális $globalref változóban
global $globalref;
$globalref[] = &$this;
// a név beállítása a kapott értékre
$this->nevBeallitas($nev);
// és kiírás
$this->nevKiiras();
}
function nevKiiras() {
echo "<br />",$this->nev;
}
function nevBeallitas($nev) {
$this->nev = $nev;
}
}
?>
Nézzük, hogy van-e különbség az $obj1 és az $obj2 objektum között. Az előbbi a = másoló operátorral készült, az utóbbi a =& referencia operátorral készült.
<?php
$obj1 = new Ize('konstruktorban beállított');
$obj1->nevKiiras();
$globalref[0]->nevKiiras();
/* kimenete:
konstruktorban beállított
konstruktorban beállított
konstruktorban beállított */
$obj2 =& new Ize('konstruktorban beállított');
$obj2->nevKiiras();
$globalref[1]->nevKiiras();
/* kimenete:
konstruktorban beállított
konstruktorban beállított
konstruktorban beállított */
?>
Szemmel láthatóan nincs semmi különbség, de valójában egy nagyon fontos különbség van a két forma között: az $obj1 és $globalref[0] _NEM_ referenciák, NEM ugyanaz a két változó. Ez azért történhet így, mert a "new" alapvetően nem referenciával tér vissza, hanem egy másolatot ad.
Hogy bebizonyítsuk, amit fent írtunk, lásd az alábbi kódot:Note: Nincsenek teljesítménybeli problémák a másolatok visszaadásakor, mivel a PHP 4 és újabb verziók referencia számlálást alkalmaznak. Legtöbbször ellenben jobb másolatokkal dolgozni referenciák helyett, mivel a referenciák képzése eltart egy kis ideig, de a másolatok képzése gyakorlatilag nem igényel időt. Ha egyik sem egy nagy tömb, vagy objektum, és a változásokat nem szeretnéd mindegyik példányban egyszerre látni, akkor másolatok használatával jobban jársz.
<?php
// Most megváltoztatjuk a nevet. Mit vársz?
// Számíthatsz arra, hogy mind $obj1 és $globalref[0] megváltozik...
$obj1->nevBeallitas('kívülről beállítva');
// mint korábban írtuk, nem ez a helyzet
$obj1->nevKiiras();
$globalref[0]->nevKiiras();
/* kimenet:
konstruktorban beállított
kívülről beállítva */
// lássuk mi a különbség az $obj2 és $globalref[1] esetén
$obj2->nevBeallitas('kívülről beállítva');
// szerencsére ezek nem csak egyenlőek, hanem éppen ugyan az
// a két változó, így $obj2->nev és $globalref[1]->nev ugyanaz
$obj2->nevKiiras();
$globalref[1]->nevKiiras();
/* kimenete:
kívülről beállítva
kívülről beállítva */
?>
Végül még egy utolsó példa, próbáld meg megérteni.
<?php
class A {
function A($i) {
$this->ertek = $i;
// próbáld meg kitalálni, miért nem kell itt referencia
$this->b = new B($this);
}
function refLetrehozas() {
$this->c = new B($this);
}
function ertekKiiras() {
echo "<br />",get_class($this),' osztály: ',$this->value;
}
}
class B {
function B(&$a) {
$this->a = &$a;
}
function ertekKiiras() {
echo "<br />",get_class($this),' osztály: ',$this->a->value;
}
}
// próbáld meg megérteni, hogy egy egyszerű másolás
// miért okoz nem várt eredményeket a *-al jelölt sorban
$a =& new A(10);
$a->refLetrehozas();
$a->ertekKiiras();
$a->b->ertekKiiras();
$a->c->ertekKiiras();
$a->ertek = 11;
$a->ertekKiiras();
$a->b->ertekKiiras(); // *
$a->c->ertekKiiras();
?>
A fenti példa a következő kimenetet adja:
A osztály: 10 B osztály: 10 B osztály: 10 A osztály: 11 B osztály: 11 B osztály: 11