Referenzen innerhalb des Konstruktors können zu verwirrenden
Resultaten führen. Dieser Abschnitt hilft, Probleme zu vermeiden.
class Foo
{
function Foo($name)
{
// eine Referenz innerhalb des globalen Arrays $globalref erstellen
global $globalref;
$globalref[] = &$this;
// setze den Namen auf den übergebenen Wert
$this->setName($name);
// und gib' ihn aus
$this->echoName();
}
function echoName()
{
echo "<br>",$this->name;
}
function setName($name)
{
$this->name = $name;
}
}
Prüfen wir, ob zwischen $bar1, die mittels
dem Operator zum Kopieren = erstellt wurde,
und $bar2, die mittels dem Referenzoperator
=& erstellt wurde, besteht...
$bar1 = new Foo('set in constructor');
$bar1->echoName();
$globalref[0]->echoName();
/* Ausgabe:
set in constructor
set in constructor
set in constructor */
$bar2 =& new Foo('set in constructor');
$bar2->echoName();
$globalref[1]->echoName();
/* Ausgabe:
set in constructor
set in constructor
set in constructor */
Scheinbar besteht kein Unterschied, aber tatsächlich existiert ein
signifikanter: $bar1 und
$globalref[0] sind NICHT referenziert, d.h. sie
sind NICHT die selbe Variable. Das kommt daher, dass "new" nicht
automatisch eine Referenz, sondern eine Kopie zurückgibt.
Anmerkung:
Das zurückgeben von Kopien anstatt von Referenzen stellt keinen
Performanceverlust dar (da PHP 4 und höher Reference Counting
verwendet). Andererseits ist es sehr oft besser, einfach mit Kopien
anstatt mit Referenzen zu arbeiten, da die Erstellung von Referenzen
etwas Zeit in Anspruch nimmt, während das Erstellen von Kopien so gut
wie keine Zeit braucht (sofern keine von ihnen ein großes Array oder
Objekt ist, und eines davon geändert wird und das/die andere/n
nachträglich. In diesem Fall wäre es besser, Referenzen zu verwenden,
um sie alle gleichzeitig zu ändern).
Um das zuvor geschriebene zu beweisen, sehen wir uns den folgenden Code an.
// nun werden wir den Namen ändern. Was erwarten Sie?
// ...dass sowohl $bar1, als auch $globalref[0] ihre Namen ändern...
$bar1->setName('set from outside');
// wie bereits zuvor erwähnt, ist dies nicht der Fall
$bar1->echoName();
$globalref[0]->echoName();
/* Ausgabe:
set from outside
set in constructor */
// lassen Sie uns den Unterschied zwischen $bar2 and $globalref[1] ansehen
$bar2->setName('set from outside');
// glücklicherweise sind sie nicht nur nicht gleich, sondern auch die selbe
// Variable; demnach sind $bar2->name und $globalref[1]->name ebenfalls gleich
$bar2->echoName();
$globalref[1]->echoName();
/* Ausgabe:
set from outside
set from outside */
Ein anderes, letztes Beispiel zum Verständnis:
class A
{
function A($i)
{
$this->value = $i;
// finden Sie heraus, warum wir hier keine Referenz benötigen
$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;
}
}
// überlegen Sie, warum hier die Verwendung einer einfachen Kopie in der
// mit * markierten Zeile zu einem unerwünschten Ergebnis führen würde
$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();
/*
Ausgabe:
class A: 10
class B: 10
class B: 10
class A: 11
class B: 11
class B: 11
*/