References μέσα σε constructorr
Η δημιουργία references μέσα σε έναν constructor μπορεί να οδηγήσει σε μπερδεμένα αποτελέσματα. Αυτό το τμήμα του εγχειριδίου θα σας βοηθήσει να αποφύγετε τέτοια προβλήματα.
<?php
class Foo
{
function Foo($name)
{
// create a reference inside the global array $globalref
global $globalref;
$globalref[] = &$this;
// set name to passed value
$this->setName($name);
// and put it out
$this->echoName();
}
function echoName()
{
echo "<br>",$this->name;
}
function setName($name)
{
$this->name = $name;
}
}
?>
Αν ελένξουμε αν υπάρχει διαφορά μεταξύ της $bar1 η οποία δημιουργήθηκε χρησιμοποιώντας ένα αντίγραφο του τελεστή = και της $bar2 που δημιουργήθηκε χρησιμοποιώντας μια αναφορά με τον τελεστή =&...
<?php
$bar1 = new Foo('set in constructor');
$bar1->echoName();
$globalref[0]->echoName();
/* output:
set in constructor
set in constructor
set in constructor */
$bar2 =& new Foo('set in constructor');
$bar2->echoName();
$globalref[1]->echoName();
/* output:
set in constructor
set in constructor
set in constructor */
?>
Με την πρώτη ματιά δεν υπάρχει διαφορά, αλλά στην πραγματικότητα υπάρχει μια πολύ σημαντική: η $bar1 και η $globalref[0] ΔΕΝ_αλληλοαναφέρονται, ΔΕΝ είναι η ίδια μεταβλητή. Αυτό συμβαίνει γιατί η "new" δεν επιστρέψει μια αναφορά πάντα, αλλά αντίθετα επιστρέφει ένα αντίγραφο.
Για να αποδείξουμε ότι μόλις είπαμε, ας δούμε τον παρακάτω κώδικα.Note: Δεν υπάρχει χάσιμο στην απόδοση (αφού η PHP 4 και μετά χρησιμοποιούν μετρητή αναφοράς) επιστρέφοντας αντίγραφα αντί για αναφορές. Αντιθέτως είναι συχνά καλύτερο να δουλεύουμε με αντίγραφα αντί για αναφορές, επειδή η δημιουργία αναφορών παίρνει κάποιο χρόνο ενώ η δημιουργία αντίγραφων ιδεατά δε θέλει καθόλου χρόνο (εκτός και αν ένα από αυτά είναι ένας μεγάλος πίνακας ή αντικείμενο και ένα από αυτά αλλάζει καθώς και τα άλλα στη συνέχεια, τότε θα ήταν σοφότερο να χρησιμοποιήσουμε αναφορές για να τα αλλάξουμε όλα συγχρόνως).
<?php
// now we will change the name. what do you expect?
// you could expect that both $bar1 and $globalref[0] change their names...
$bar1->setName('set from outside');
// as mentioned before this is not the case.
$bar1->echoName();
$globalref[0]->echoName();
/* output:
set from outside
set in constructor */
// let us see what is different with $bar2 and $globalref[1]
$bar2->setName('set from outside');
// luckily they are not only equal, they are the same variable
// thus $bar2->name and $globalref[1]->name are the same too
$bar2->echoName();
$globalref[1]->echoName();
/* output:
set from outside
set from outside */
?>
Ακόμη ένα τελικό παράδειγμα, προσπαθήστε να το κατανοήσετε.
<?php
class A
{
function A($i)
{
$this->value = $i;
// try to figure out why we do not need a reference here
$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;
}
}
// try to undestand why using a simple copy here would yield
// in an undesired result in the *-marked line
$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();
/*
output:
class A: 10
class B: 10
class B: 10
class A: 11
class B: 11
class B: 11
*/
?>