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.

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.

$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.

Megjegyzés: 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.

Hogy bebizonyítsuk, amit fent írtunk, lásd az alábbi kódot:

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

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();

/*
kimenete:
A osztály: 10
B osztály: 10
B osztály: 10
A osztály: 11
B osztály: 11
B osztály: 11
*/