Класове и обекти (PHP 4)
PHP Manual

Референции в конструктора

Създаването на референции в конструктора може да доведе до объркващи резултати. Този раздел, написан във вид на ръководство, може да ви помогне да избегнете подобни проблеми.

<?php
class Foo {
    function 
Foo($name) {
        
// създаване на референция в глобалния масив $globalref
        
global $globalref;
        
$globalref[] = &$this;
        
// установяне на името на предадената стойност
        
$this->setName($name);
        
// и извеждане
        
$this->echoName();
    }

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

Нека сега да проверим дали има разлика между $bar1, създадена чрез оператора за копиране = и $bar2, създадена чрез оператора за референции - =&

<?php
$bar1 
= new Foo('установяване в конструктора');
$bar1->echoName();
$globalref[0]->echoName();

/* изход:
установяване в конструктора
установяване в конструктора
установяване в конструктора */

$bar2 =& new Foo('установяване в конструктора');
$bar2->echoName();
$globalref[1]->echoName();

/* изход:
установяване в конструктора
установяване в конструктора
установяване в конструктора */
?>

Очевидно няма разлика, но всъщност има една значителна разлика: $bar1 и $globalref[0] не са извикани по референция и не са една и съща променлива. Това е така, тъй като операторът "new" по подразбиране връща не референция, а копие.

Забележка: Няма намаляване на производителността (след като от PHP 4 се използва брояч на референциите) при връщане на копия вместо референции. Точно обратното, често е по-добре просто да се работи с копия, вместо с референции, тъй като създаването на референции отнема известно време, докато създаването на копие фактически не отнема време (освен ако никое от тях не е голям масив или обект и един от тях е променен, а в последствие и останалите. В този случай ще бъде по-добре да се използват референции, за да бъдат променени едновременно).

За да докажем написаното по-горе, нека погледнем кода отдолу.

<?php
// сега ще променим името. Какво очаквате да стане?
// можете да очаквате, че $bar1 и $globalref[0] ще са с променени имена...
$bar1->setName('установяване от вън');

// както споменахме по-горе, това няма да стане
$bar1->echoName();
$globalref[0]->echoName();

/* изход:
установяване от вън
установяване в конструктора */

// нека сега видим каква е разликата между $bar2 и $globalref[1]
$bar2->setName('установяване от вън');

// за щастие те не само са равни, те представляват една и съща променлива
// така че,  $bar2->name и $globalref[1]->name също са една и съща променлива
$bar2->echoName();
$globalref[1]->echoName();

/* изход:
установяване от вън
установяване от вън */
?>

Още един, последен пример, опитайте се да го разберете.

<?php
class {
    function 
A($i) {
        
$this->value $i;
        
// опитайте се да разберете защо нямаме нужда от референция тук
        
$this->= new B($this);
    }

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

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


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

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

// опитайте се да разберете, защо използването на обикновено копие тук,
// ще доведе до нежелани резултати в реда отбелязан със *.
$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();

?>

Примерът по-горе ще изведе:

class A: 10
class B: 10
class B: 10
class A: 11
class B: 11
class B: 11


Класове и обекти (PHP 4)
PHP Manual