PHP Velho Oeste 2024

Referencias dentro del constructor

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.

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

Para probar lo que esta escrito aquí arriba observar el código siguiente.
<?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 {
    function 
A($i) {
        
$this->value $i;
        
// intente entender por qué no es necesaria una referencia aquí
        
$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;
    }
}

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

add a note add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top