R�f�rences dans un constructeur

Cr�er des r�f�rences dans un constructeur peut conduire � des r�sultats �tranges. Ce tutoriel vous guide pour �viter ces probl�mes.

<?php
class Foo {
    function 
Foo($name) {
        
// cr�e une r�f�rence dans le tableau global $globalref
        
global $globalref;
        
$globalref[] = &$this;
        
// donne le nom de la variable
        
$this->setName($name);
        
// et l'affiche
        
$this->echoName();
    }

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

V�rifions maintenant qu'il y a une diff�rence entre $bar1 qui a �t� cr�� avec = et $bar2 qui a �t� cr�� avec l'op�rateur de r�f�rence =& :

<?php
$bar1 
= new Foo('cr�e dans le constructeur');
$bar1->echoName();
$globalref[0]->echoName();

/* affiche :
cr�e dans le constructeur
cr�e dans le constructeur
cr�e dans le constructeur */

$bar2 =&new foo('cr�e dans le constructeur');
$bar2->echoName();
$globalref[1]->echoName();

/* affiche :
cr�e dans le constructeur
cr�e dans le constructeur
cr�e dans le constructeur */
?>

Apparemment, il n'y a pas de diff�rence, mais en fait, il y en a une significative : $bar1 et $globalref[0] ne sont pas r�f�renc�es, ces deux variables sont diff�rentes. Cela est d� au fait que l'op�rateur new ne retourne par de r�f�rence, mais retourne une copie.

Note: Il n'y a aucune perte de performances (puisque PHP 4 utilise un compteur de r�f�rences) � retourner des copies au lieu de r�f�rences. Au contraire, il est souvent mieux de travailler sur les copies plut�t que sur les r�f�rences, car cr�er une r�f�rence prend un peu plus de temps que de cr�er une copie qui ne prend virtuellement pas de temps (� moins de cr�er un tableau g�ant ou un objet monstrueux, auquel cas il est pr�f�rable de passer par des r�f�rences).

Pour prouver ceci, regardez le code suivant :

<?php
// maintenant, nous allons changer de nom. Qu'attendez-vous ?
// Vous pouvez vous attendre � ce que les deux variables $bar
// et $globalref[0] changent de nom...
$bar1->setName('modifi�');

// comme pr�dit, ce n'est pas le cas
$bar1->echoName();
$globalref[0]->echoName();

/* affiche :
modifi�
cr�e dans le constructeur
*/

// quelle est la diff�rence entre $bar2 et $globalref[1]
$bar2->setName('modifi�');

// Heureusement, elles sont non seulement �gales, mais
// elles repr�sentent la m�me variable.
// donc $bar2->Name et $globalref[1]->Name sont les m�mes
$bar2->echoName();
$globalref[1]->echoName();

/* affiche :
  modifi�
  modifi� */
?>

Un dernier exemple pour bien comprendre.

<?php
class {
    function 
A($i) {
        
$this->value $i;
        
// Essayez de comprendre on n'a pas besoin de
        // r�f�rence ici
        
$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;
    }
}
// Essayez de comprendre pourquoi une copie simple va
// conduire � un r�sultat ind�sirable �
// la ligne marqu�e d'une �toile
$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();

?>

L'exemple ci-dessus va afficher :

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