Objekty vystupující jako argument operátoru přiřazení ( =
) jsou podle mě další velkou nepříjemností, která vás v PHP čeká. Narozdíl od jiných programovacích jazyků v PHP příkazem
$promenna = $objekt;
přiřadíte do proměnné $promenna
kopii (!) objektu uloženého pod proměnnou $objekt
. Tento fakt se musí obcházet použitím odkazů (operátoru &
). Dlouho jsem si na tuto skutečnost nemohl zvyknout a byla příčinou mnoha nechutných chyb. Pro lepší pochopení problému uvedu příklad:
class NejakaTrida {
var $hodnota;
function NejakaTrida($h) {
$this->hodnota = $h;
}
}
function zobraz() {
global $a, $b, $c;
print '<p>';
print 'Hodnota $a je ' . $a->hodnota . '<BR>';
print 'Hodnota $b je ' . $b->hodnota . '<BR>';
print 'Hodnota $c je ' . $c->hodnota . '<BR>';
}
$a = new NejakaTrida('AAA');
$b = $a;
$c =& $a;
zobraz();
$b->hodnota = 'BBB';
zobraz();
$c->hodnota = 'CCC';
zobraz();
Výsledkem kódu bude:
Hodnota $a je AAA
Hodnota $b je AAA
Hodnota $c je AAA
Hodnota $a je AAA
Hodnota $b je BBB
Hodnota $c je AAA
Hodnota $a je CCC
Hodnota $b je BBB
Hodnota $c je CCC
Pokud k přiřazení objektu do proměnné použijeme příkaz typu
$b = $a;
uloží se do $b
kopie objektu $a
. Vznikne tak další samostatný objekt, který nemá s prvním nic společného (až na třídu, ke které oba patří).
K tomu, abyste do nové proměnné ( $c
) uložili odkaz na tentýž objekt ( $a
), musíte použít konstrukci
$c =& $a;
Od této chvíle je $c
jen jiné jméno pro objekt uložený v $a
– obě proměnné odkazují na tentýž objekt.
Často můžete potřebovat metodu, která jako argument požaduje odkaz na objekt. Potom před název argumentu v hlavičce musíte umístit znak &
:
function ptakovina(&$odkaz_na_objekt) {
# ...
}
Malá ukázka použití v praxi:
/*
Kontejnerová třída, která ukládá do pole různé objekty
a na požádání volá jejich metody zobraz()
*/
class Kontejner {
var $polozky;
# vlož odkaz na objekt do kontejneru
function vloz(&$obj) {
$this->polozky[] =& $obj;
}
# zobraz všechny objekty v kontejneru
function zobraz() {
for ($x = 0; $x < count($this->polozky); $x++) {
$this->polozky[$x]->zobraz();
}
}
}
/*
Jednoduchá třída implementovaná proto, abychom
měli do kontejneru co vkládat
*/
class Odstavec {
var $text;
# konstruktor
function Odstavec($t = '') {
$this->text = $t;
}
# zobrazovací metoda
function zobraz() {
print '<P>Text odstavce: ' . $this->text . '</P>';
}
}
$stranka = new Kontejner();
$a = new Odstavec('Odstavec 1');
$b = new Odstavec('Odstavec 2');
$c = new Odstavec();
$stranka->vloz($a);
$stranka->vloz($b);
$stranka->vloz($c);
$c->text = 'Odstavec 3';
$stranka->zobraz();
Vynecháním všech &
v metodě vloz()
třídy Kontejner
byste si zadělali na nepříjemnou chybu. Místo očekávaného výstupu:
Text odstavce: Odstavec 1
Text odstavce: Odstavec 2
Text odstavce: Odstavec 3
byste se dočkali pouze tohoto:
Text odstavce: Odstavec 1
Text odstavce: Odstavec 2
Text odstavce:
Je to proto, že objekt $c
jsme kontejneru $stranka
předali dříve, než nabyl textu 'Odstavec 3'
. Bez použití odkazů bychom v kontejneru uchovávali pouze kopie objektů $a
, $b
, $c
, a tedy příkaz $c->text = 'Odstavec 3'
by se objektu uloženého v kontejneru vůbec netýkal.
Potřebujete-li vyrobit funkci či metodu, která vrací odkaz na objekt, musí její hlavička vypadat takto:
function &ziskej($parametr) {
# ...
return $objekt;
}
Bez &
před názvem funkce bychom příkazem return $objekt
vrátili pouze kopii objektu $objekt
.
Poznámka: Machrování s odkazy se dá obecně použít na proměnnou jakéhokoliv typu. Podrobněji o odkazech viz manuál k PHP.
Dokončení příště…