Hlavní navigace

PHP v objetí objektů (5)

Michal Burda 13. 8. 2001

V předposledním pokračování seriálu o objektově orientovaném programování v PHP si ukážeme jednu záludnost, která na programátory číhá v nevinně vyhlížejícím operátoru přiřazení (=).

Objekty a operátor přiřazení

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ě…

Našli jste v článku chybu?

4. 3. 2008 14:57

NOVEJ MODEL (neregistrovaný)
PHP 3 opravdu nepoužívej

23. 8. 2001 15:52

Vladislav Švadlenka (neregistrovaný)

Omlouvám se předem za začátečnický dotaz.
Syntaxi $c =& $a; kde c a a jsou objekty mi PHP3 nebere.
Existuje nějaká finta, jak v PHP3 komunikavat mezi objekty?
Děkuji





Měšec.cz: mBank cenzuruje, zrušila mFórum

mBank cenzuruje, zrušila mFórum

Lupa.cz: UX přestává pro firmy být magie

UX přestává pro firmy být magie

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Lupa.cz: Avast po spojení s AVG propustí 700 lidí

Avast po spojení s AVG propustí 700 lidí

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

Lupa.cz: Teletext je „internetem hipsterů“

Teletext je „internetem hipsterů“

120na80.cz: Na ucho teplý, nebo studený obklad?

Na ucho teplý, nebo studený obklad?

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

120na80.cz: Jak oddálit Alzheimera?

Jak oddálit Alzheimera?

120na80.cz: Horní cesty dýchací. Zkuste fytofarmaka

Horní cesty dýchací. Zkuste fytofarmaka

Vitalia.cz: Často čůrá a má žízeň? Příznaky dětské cukrovky

Často čůrá a má žízeň? Příznaky dětské cukrovky

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Vitalia.cz: Manželka je bio, ale na sex moc není

Manželka je bio, ale na sex moc není

120na80.cz: Boreliózu nelze žádným testem prokázat

Boreliózu nelze žádným testem prokázat

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

Měšec.cz: Přejete si číslo účtu na přání?

Přejete si číslo účtu na přání?