Hlavní navigace

PHP v objetí objektů (3)

Michal Burda

Dnes si vezmeme na mušku dědičnost tříd a její použití v PHP skriptech. Ukážeme si také, jak předefinovat zděděné metody a jak jejich původní verze v předefinovaných metodách volat.

Dědičnost

V této chvíli máme vytvořen objekt, který jakžtakž „chodí“. Naplno jsme si přitom vychutnali výhody zapouzdření výkonných rutin a dat (umístění dat i funkcí do jedné entity). Může se však stát, že nám naše Menu po čase přestane vyhovovat. Najednou zjistíme, že občas potřebujeme menu umisťovat doprostřed stránky, a tak bychom chtěli, aby se to provádělo automaticky. Původní Menu ale často používáme, a proto chceme, aby zůstalo takové, jaké je. Na řadu proto přichází další mocný nástroj objektově orientovaného programování, dědičnost.

(Tohle je trochu vykonstruovaný příklad. V žádném případě tím nechci říct, abyste kvůli každé prkotině, kterou chcete do objektů naimplementovat, vytvářeli nové třídy. V praxi by se to všechno docela určitě fláklo do původní třídy Menu.) 

Vyrobíme novou třídu jménem CentrovaneMenu, která převezme všechny dobré vlastnosti původního Menu a navíc přidá nějaké další:

class CentrovaneMenu extends Menu {
  var $centrovat = false;

  # novy konstruktor
  function CentrovaneMenu($polozky = array()) {
    $this->Menu($polozky);
  }

  # centrovat menu?
  function centrovat($centr = true) {
    $this->centrovat = $centr;
  }

  # ještě tomu něco chybí...
} 

V definici třídy nám přibylo další klíčové slůvko: extends. Za něj píšeme název třídy, ze které bude dědit (říká se jí parent class, rodičovská třída nebo ancestor, předek). PHP neumí mnohonásobnou dědičnost, takže každý objekt může mít nejvýše jednoho předka. Třída CentrovaneMenu dědí své vlastnosti z třídy Menu  – má všechny atributy a funkce stejné jako její rodičovská třída. Dodefinovali jsme navíc ještě jeden atribut, $centrovat, který určuje, má-li se menu vystředit.

Pro novou třídu jsme vytvořili také nový konstruktor. Nebylo to v zásadě nutné, protože konstruktor CentrovaneMenu() jenom volá zděděný konstruktor Menu(), ale myslím si, že je dobrým zvykem, ke každé třídě automaticky vytvářet konstruktor nový – s největší pravděpodobností jej dříve nebo později budete stejně potřebovat. (Všimněte si, že se zděděný konstruktor volá stejně jako jakákoliv obyčejná metoda.)

Třída CentrovaneMenu taková, jak ji máme nyní definovánu, bude samozřejmě plně funkční. Zdědila totiž všechny metody i atributy třídy Menu, takže se bude přesně jako Menu chovat. Nám zbývá doplnit metodu zobraz(), aby reagovala i na hodnotu atributu centrovat.

Předefinování metody

class CentrovaneMenu extends Menu {
  # atribut, konstruktor a metoda viz vyse...

  # predefinovana metoda zobraz
  function zobraz() {
    if ($this->centrovat) {
      print '<CENTER>';
    }
    Menu::zobraz();
    if ($this->centrovat) {
      print '</CENTER>';
    }
  }
} 

Co se stalo nyní? Předefinovali jsme metodu zobraz(). Ve třídě Menu byla metoda zobraz() již nějakým způsobem definována. Třída CentrovaneMenu její definici zdědila, ale jelikož nám plně nevyhovuje, uvedli jsme definici novou. Původní zobraz() byla dobrá až na malý nedostatek: necentrovala. Proto podle nové definice požadujeme, aby metoda nejprve podle hodnoty atributu centrovat vypsala tag <CENTER>, poté zavolala předefinovanou metodu zobraz() třídy Menu, a nakonec vypsala ukončovací tag  </CENTER>.

Všimněte si, jak se překrytá metoda zobraz() třídy Menu volala:

Menu::zobraz(); 

Obyčejný zápis

$this->zobraz(); 

nelze použít, protože by to znamenalo rekurzivní volání metody zobraz(). Muselo se proto přijít s novou syntaktickou konstrukcí: název třídy, operátor příslušnosti ( ::) a název metody. Podle takovéhoto zápisu už PHP pozná, kterou verzi metody zobraz() vlastně chcete volat.

Poznámka: Na tomto místě si dovoluji znovu poukázat na rozdíl mezi voláním zděděného konstruktoru ($this->RodicovskaTrida()) a voláním předefinované metody (NazevTridy::na­zevMetody()). Protože u konstruktorů nemůže dojít k omylu, používá se standardní volání metody.

Poznámka: Konstrukce NazevTridy::na­zevMetody() se dá využít i k zajištění toho, aby se vždy volala požadovaná verze metody, nicméně obvykle se to nedělá, protože si tak zavíráme vrátka k polymorfizmu (viz později).

Tolik pro dnešek o PHP a objektově orientovaném programování. Konstrukce NazevTridy::nazevMetody() se používá i k tzv. statickému volání metod. Podrobněji se tomu budeme věnovat v příštím dílu.

Našli jste v článku chybu?