Hlavní navigace

PHP v objetí objektů (6)

20. 8. 2001
Doba čtení: 4 minuty

Sdílet

Dnešním dílem náš seriál o objektově orientovaném programování v PHP dokončíme. Popíšeme si standardní funkce PHP pro práci s objekty a zamyslíme se nad zvyklostmi, které by měl OOP programátor v PHP dodržovat.
Další funkce

Kromě mechanismu tříd nabízí PHP ještě několik funkcí, které vám práci s objekty mohou zpříjemnit. Všechny jsou popsány v manuálu k PHP, proto zde jen v rychlosti:

 Funkce      Návratová hodnota     Popis
get_class($objekt)  řetězec   Funkce vrací název třídy, jejíž instancí je objekt $objekt.
get_parent_class($objekt)   řetězec   Funkce vrací název předka (parent class) třídy, jejíž instancí je objekt $objekt.
get_class_methods($nazev_tridy)     pole řetězců     Funkce vrací pole názvů metod třídy, jejíž název je předán v řetězcovém argumentu $nazev_tridy. Pole obsahuje názvy všech dostupných metod, tedy i metod zděděných.
get_class_vars($nazev_tridy)    pole řetězců     Funkce vrací pole názvů deklarovaných atributů třídy, jejíž název je předán v řetězcovém argumentu $nazev_tridy. Pole obsahuje názvy všech atributů deklarovaných pomocí var (i zděděných).
get_object_vars($objekt)    asociativní pole   Funkce vrací asociativní pole atributů objektu $objekt. (Klíč = název atributu)
is_subclass_of($objekt, $rodicovska_trida)  bool    Funkce vrací true, jestliže objekt $objekt je instancí třídy, která je podtřídou třídy specifikované řetězcem $rodicovska_trida. Jinak vrátí false (i tehdy, je-li $objekt instancí třídy $rodicovska_trida!).
class_exists($nazev_tridy)  bool    Funkce vrátí true, jestliže třída daná řetězcem $nazev_tridy existuje. Jinak vrátí false.
method_exists($objekt, $nazev_metody)   bool    Funkce vrátí true, jestliže objekt $objekt disponuje metodou s názvem $nazev_metody. Jinak vrátí false.
get_declared_classes()  pole řetězců     Funkce vrátí pole názvů deklarovaných tříd. V některých verzích PHP může vracet i názvy některých speciálních tříd -- viz manuál k PHP.
call_user_method($nazev_metody, $objekt, $parametry...)     různé     Funkce zavolá na objekt $objekt metodu s názvem $nazev_metody a předá jí případné $parametry.... Vrací hodnotu získanou z výsledku volání dané metody. 

Názvy tříd a metod vracené těmito funkcemi jsou vždy automaticky převedeny na malá písmena abecedy.

Dobré mravy

Chcete-li v PHP psát objektově, musíte více než kde jinde pamatovat na dobré mravy a nutit se psát čitelně. PHP, narozdíl od C++ či Javy, neprovádí žádné kontroly typů a chybu v syntaxi rozezná, až když na ni při zpracování narazí. To je zdrojem mnoha nepříjemných chyb, které se špatně hledají, a části z nich se vyvarujete, budete-li důsledně dodržovat jisté konvence a úmluvy.

Zcela byste se měli vyvarovat statických volání metod tříd uvnitř jiné třídy za jiným účelem, než je volání předefinované funkce – ve 4. části jste mohli vidět, jaké psí kusy to dělá s proměnnou  $this.

Všechny atributy, které chcete používat, byste měli důsledně deklarovat v sekci var definice třídy a nespoléhat se na skutečnost, že v případě neexistence třídního atributu vytvoří PHP atribut objektu.

Také byste si měli vytvořit nějaké konvence pojmenovávání. Proč si neodskočit do Javy:

  • názvy tříd – psát dohromady, každé slovo názvu začíná velkým písmenem (např.  MujUkazkovyNazevTridy)
  • názvy metod – psát dohromady, první písmeno každého slova kromě prvního velké (např.  nejakaMetoda())
  • názvy atributů – psát malými písmeny, slova oddělovat podtržítkem (např.  $nejaky_atribut)

Váš kód se tak stane čitelnějším a přehlednějším.

PHP neumožňuje skrývání (pomocí konstrukcí private jako v C++ či Javě), a to přináší další nepříjemnosti. Dobrým zvykem proto může být předsazování podtržítka '_' před atributy a metody, které nejsou určeny k použití z vnějšku. Lehce tak dáte uživateli vašich tříd (nebo sami sobě) najevo, které metody se mohou používat přímo a které ne.

Někteří programátoři si zvykli na pravidlo nepřistupovat z vnějšku k atributům objektů přímo, ale vytvářet speciální metody k tomu určené:

/*
implementace jednoducheho seznamu zbozi ve
virtualnim obchode
*/
class SeznamZbozi {
  var $_nazev_seznamu; # nazev seznamu zboží
  var $_pocet;         # pocet položek, jen ke čtení!
  var $_polozky;       # pole položek

  # metody pro práci s názvem seznamu
  function vlozNazev($novy_nazev) {
    $this->_nazev_seznamu = $novy_nazev;
  }

  function vratNazev() {
    return $this->_nazev_seznamu;
  }

  # metoda pro práci s atributem $pocet
  function vratPocet() {
    return $this->_pocet;
  }

  # ...další metody
} 

Ke každému atributu definujte dvojici metod vloz... a vrat... (nebo anglicky set... a get...) a k atribitu přistupujte vyhradně jejich prostřednictvím. Má to hned dvě výhody. Za prvé, položkám, které chcete mít z vnějšku nepřístupné nebo jen ke čtení, uvedené metody nenapíšete nebo napíšete jenom verzi vrat  – a tak ihned vidíte, co si ke kterému atributu můžete dovolit. Druhou výhodou je možnost přidat později k ukládání nebo čtení hodnoty atributu nejaké akce navíc.

Například chcete pro ladicí účely vědět o každém zápisu hodnoty do atributu $_nazev_seznamu. Jednoduše upravíte metodu  vlozNazev():

function vlozNazev($novy_nazev) {
  print 'Pozor! Změna názvu seznamu!';
  print ' Stará hodnota: ' . $this->_nazev_seznamu;
  print ' Nová hodnota: ' . $novy_nazev;
  $this->_nazev_seznamu = $novy_nazev;
} 

Nebo po čase zjistíte, že atribut $pocet naší třídy SeznamZbozi je zbytečný, tak ho odstraníte a metodu vratPocet() přepíšete:

function vratPocet() {
  return count($this->_polozky);
} 

Vše bez nebezpečí, že vám zbytek kódu, který třídu SeznamZbozi používá, přestane fungovat.

CS24_early

Závěr

Jak sami vidíte, programovat objektově v PHP lze. Otázkou však zůstává, nakolik je to příjemné a výhodné. Dostanete do rukou silné nástroje jako dědičnost a polymorfizmus, ale na druhou stranu špatným stylem programování si zavlečete do kódu mnoho nepříjemných chyb. Absence jakýchkoliv kontrol typů je zde citelnou nevýhodou. Pro někoho nezvyklé vlastnosti operátoru přiřazení stejně jako nulová podpora pro abstraktní třídy a nezabezpečené volání předefinovaných metod, to všechno je matoucí a bývá zdrojem chyb. A tak odpověď na otázku, zda PHP s OOP ano, či ne, zůstává jako vždy jen a jen na vás.

Byl pro vás článek přínosný?

Autor článku

Michal Burda vystudoval informatiku a aplikovanou matematiku a nyní pracuje na Ostravské univerzitě jako odborný asistent. Zajímá se o data mining, Javu a Linux.