Reference znotraj konstruktorja

Ustvarjanje reference znotraj konstruktorja lahko pripelje do čudnih rezultatov. Naslednje informacije vam bodo pomagale izogniti se temu problemu.

class Foo
{
    function Foo($name)
    {
        // ustvari referenco znotraj globalne tabele $globalref
        global $globalref;
        $globalref[] = &$this;
        // nastavi name na podano vrednost
        $this->setName($name);
        // izpisi to vrednost
        $this->echoName();
    }

    function echoName()
    {
        echo "<br>",$this->name;
    }
    
    function setName($name)
    {
        $this->name = $name;
    }
}

Pa poglejmo, če je razlika med $bar1, ki je bila ustvarjena z = opratorjem in $bar2, ki je bila ustvarjena z referenčnim operatorjem =& ...

$bar1 = new Foo('nastavljen v konstruktorju');
$bar1->echoName();
$globalref[0]->echoName();

/* izpis:
nastavljen v konstruktorju
nastavljen v konstruktorju
nastavljen v konstruktorju */

$bar2 =& new Foo('nastavljen v konstruktorju');
$bar2->echoName();
$globalref[1]->echoName();

/* izpis:
nastavljen v konstruktorju
nastavljen v konstruktorju
nastavljen v konstruktorju */

Na pogled ni razlike, vedar obstaja ena zelo pomembna: $bar1 in $globalref[0] _NISTA_ referenčni in ista isti spremenljivki. To je zato, ker "new" ne vrne reference, ampak vrne kopijo.

Opomba: Nič ne izgubimo na hitrosti (od PHP 4 naprej, uporablja štetje referenc), če uporabljamo kopije namesto referenc. Prav nasprotno, ponavadi je bolje preprosto delati z kopijami, ker ustvarjanje referenc traja nekaj časa, za ustvarjanje kopije pa ne porabimo praktično nič časa (razen, če je to kaksna velika tabela ali objekt in spreminjamo enega za drugim, kjer bi bilo pametneje uporabiti referenco, kjer bi spremenili vse hkrati).

Za obrazložitev, si poglejte spodnjo kodo.

// sedaj bomo zamenjali name. Kaj pricakujete?
// lahko bi pricakovali da se bosta $bar in $globalref[0] spremenila ...
$bar1->setName('nastavljen od zunaj');

// kot je omenjeno zgoraj, se to ne zgodi.
$bar1->echoName();
$globalref[0]->echoName();

/* output:
nastavljen do zunaj
nastavljen v konstruktorju */

// poglejmo kaksna je razlika z $bar2 in $globalref[1]
$bar2->setName('nastavljen od zunaj');

// na sreco niso samo enake, temvec tudi iste spremenljivke
// torej sta $bar2->name in $globalref[1]->name isti
$bar2->echoName();
$globalref[1]->echoName();

/* izpis:
nastavljen od zunaj
nastavljen od zunaj */

Še en primer, poskusite ga razumeti.

class A
{
    function A($i)
    {
        $this->value = $i;
    // poskusite ugotoviti zakaj ne potrebujemo reference tukaj
        $this->b = new B($this);
    }

    function createRef()
    {
        $this->c = new B($this);
    }

    function echoValue()
    {
        echo "<br>","razred ",get_class($this),': ',$this->value;
    }
}


class B
{
    function B(&$a)
    {
        $this->a = &$a;
    }

    function echoValue()
    {
        echo "<br>","razred ",get_class($this),': ',$this->a->value;
    }
}

// poskusite ugotoviti zakaj tukaj navadna kopija nebi prinesla
// zeljenih rezultatov v vrstici oznaceni z *
$a =& new A(10);
$a->createRef();

$a->echoValue();
$a->b->echoValue();
$a->c->echoValue();

$a->value = 11;

$a->echoValue();
$a->b->echoValue(); // *
$a->c->echoValue();

/*
izpis:
razred A: 10
razred B: 10
razred B: 10
razred A: 11
razred B: 11
razred B: 11
*/