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 A {
function A($i) {
$this->value = $i;
// Essayez de comprendre on n'a pas besoin de
// r�f�rence ici
$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;
}
}
// 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