A criação de referências em construtores pode gerar resultados confusos. Esta seção tentará ajudá-lo e evitar essas situações.
class Foo { function Foo($name) { // cria uma referencia dentro do array global $globalref global $globalref; $globalref[] = &$this; // configura o nome conforme o parametro $this->setName($name); // e o mostra $this->echoName(); } function echoName() { echo "<br>",$this->name; } function setName($name) { $this->name = $name; } } |
Vamos verificar, abaixo, se há alguma diferença entre $bar1, que foi criado usando operador de cópia =, e $bar2 que foi criado usando o operador de referência =& ...
$bar1 = new Foo('configurado no construtor'); $bar1->echoName(); $globalref[0]->echoName(); /* saida: configurado no construtor configurado no construtor configurado no construtor */ $bar2 =& new Foo('configurado no construtor'); $bar2->echoName(); $globalref[1]->echoName(); /* saida: configurado no construtor configurado no construtor configurado no construtor */ |
Aparentemente não há nenhuma diferença, mas de fato há uma muito significativa: $bar1 e $globalref[0] não se referenciam, elas NÃO são a mesma variável. Isto acontece porque "new" não retorna uma referência por default. Ao invés, retorna uma cópia.
Nota: Isto não causa perda de performance (desde que o PHP 4 usa a contagem de referências) retornando copias em vez de referências. Do contrário, isso oferece melhora por simplificar o trabalho com cópias ao invés de referências, porque a criação de referências toma mais tempo enquanto a criação de cópias virtualmente não toma tempo algum (a não ser no caso de grandes arrays ou objetos, onde um deles é modificado e o(s) outro(s) também na seqüência, então é melhor usar referências para mudar todos ao mesmo tempo).
// Agora nos vamos mudar o nome. O que voce espera? // Voce pode acreditar que ambos $bar1 e $globalref[0] mudem seus nomes... $bar1->setName('configurado por fora'); // Como mencionado, este nao eh o caso. $bar1->echoName(); $globalref[0]->echoName(); /* output: configurado por fora configurado no construtor */ // Agora vamos ver a diferenca entre $bar2 e $globalref[1] $bar2->setName('configurado por fora'); // Por sorte, eles nao sao apenas iguais, eles sao a mesma variavel // Assim, $bar2->name e $globalref[1]->name sao o mesmo tambem $bar2->echoName(); $globalref[1]->echoName(); /* output: configurado por fora configurado por fora */ |
E apenas mais um exemplo final. Entenda-o com cuidado.
class A { function A($i) { $this->value = $i; // tente entender porque aqui nos nao precisamos de referencia $this->b = new B($this); } function createRef() { $this->c = new B($this); } function echoValue() { echo "<br>","classe ",get_class($this),': ',$this->value; } } class B { function B(&$a) { $this->a = &$a; } function echoValue() { echo "<br>","classe ",get_class($this),': ',$this->a->value; } } // Tente entender porque usando uma simples copia aqui ter // um resultado indesejavel na linha marcada com * $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(); /* output: classe A: 10 classe B: 10 classe B: 10 classe A: 11 classe B: 11 classe B: 11 */ |