Crear referencias dentro del cosntructor puede llevar a resultados confusos. Esta sección a manera de guía ayuda a evitar problemas.
<?php
class Foo {
function Foo($name) {
// crear una referencia dentro de la matriz global $globalref
global $globalref;
$globalref[] = &$this;
// hacer que el nombre sea el valor que ha sido pasado
$this->setName($name);
// y mostrarlo
$this->echoName();
}
function echoName() {
echo "<br />", $this->name;
}
function setName($name) {
$this->name = $name;
}
}
?>
Revisar si hay alguna diferencia entre $bar1 que ha sido creada usando el operador de copiado = y $bar2 que ha sido creada utilzando el operador de referencia =&...
<?php
$bar1 = new Foo('set in constructor');
$bar1->echoName();
$globalref[0]->echoName();
/* salida:
set in constructor
set in constructor
set in constructor */
$bar2 =& new Foo('set in constructor');
$bar2->echoName();
$globalref[1]->echoName();
/* salida:
set in constructor
set in constructor
set in constructor */
?>
Aparentemente no hay diferencia, pero de hecho existe una muy significativa: $bar1 y $globalref[0] _NO_ están referenciadas, NO son la misma variable. Esto es porque "new" no devuelve una referencia por omisión, en vez de ello devuelve una copia.
Para probar lo que esta escrito aquí arriba observar el código siguiente.Nota: No hay pérdida de desempeño (ya que PHP 4 y superiores utilizan conteo de referencias) al devolver copias en vez de referencias. Al contrario la mayor parte del tiempo es mejor simplemente trabajar con copias en vez de referencias, porque crear referencias toma algo de tiempo mientras que crear copias virtualmente no toma tiempo (a menos que una de ellas sea un objeto o matriz grande y una de ellas es cambiada y la(las) otra(s) subsecuentemente también, entonces sería sabio usar referencias para cambiarlas a todas concurrentemente).
<?php
// ahora se cambiará el nombre. ¿Qué esperabas?
// se podría esperar que $bar1 y $globalref[0] ambas cambien sus nombres...
$bar1->setName('set from outside');
// como se mencionó antes este no es el caso.
$bar1->echoName();
$globalref[0]->echoName();
/* salida:
set from outside
set in constructor */
// veamos que es diferente con $bar2 y $globalref[1]
$bar2->setName('set from outside');
// afortunadamente no sólo son iguales, son la misma variable
// así $bar2->name y $globalref[1]->name son las mismas también
$bar2->echoName();
$globalref[1]->echoName();
/* salida:
set from outside
set from outside */
?>
Otro ejemplo final, intente comprenderlo.
<?php
class A {
function A($i) {
$this->value = $i;
// intente entender por qué no es necesaria una referencia aquí
$this->b = new B($this);
}
function createRef() {
$this->c = new B($this);
}
function echoValue() {
echo "<br />","class ",get_class($this),': ',$this->value;
}
}
class B {
function B(&$a) {
$this->a = &$a;
}
function echoValue() {
echo "<br />","class ",get_class($this),': ',$this->a->value;
}
}
// intente entender por qué usar una copia simple aquí terminaría
// en un resultado no deseado en la línea marcada con *
$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();
?>
El resultado del ejemplo sería:
class A: 10 class B: 10 class B: 10 class A: 11 class B: 11 class B: 11