Únor 12th, 2007OOP v PHP 3 - interface

Interface (rozhranní) je jedna z věcí, která je často přeceňována nebo nedoceňována. Oč vlastně jde?

Představte si, že se dostanete do situace, kdy budete potřebovat určit, že objekt „umí“ něco, co se od něj očekává, ale nejsme si jistí, zda to tak je :)

Uvedu příklad:
Mám objekty manželka, děti, papoušek, pes a tchýně. Všechny objekty mohu považovat za součást rodiny. Problém nastává ve chvíli, kdy bych potřeboval vědět, kdo z uvedených rodinných příslušníků umí vařit. Vaření si mohu představit jako metodu, která mi provede danný úkon a vytvoří (vrátí) objekt jídlo.

Toto je klasický příklad, kdy mohu použít (implementovat) interface. Nejdříve si vytvořím vlastní interface, které bude obsahovat metodu uvarJidlo().

<?php
interface UmiVarit
{
      public function uvarJidlo(Jidlo $jidlo);
{
 ?>

Nyní mám rozhranní, které je potřeba implementovat na ty třídy, které budou moci vařit jídlo.

<?php
class Manzelka implements UmiVarit
{
      public function uvarJidlo(Jidlo $jidlo)
      {
            return "manzelka uvarila: ". $jidlo->getNazev();
      }
}?>

Takže nyní, když zavolám objekt (rodinného příslušníka), jsem schopen určit, který z nich vařit umí a který nikoli.

<?php
$rodina[] = new Manzelka();
$rodina[] = new Tchyne();
$rodina[] = new Pes();
foreach($rodina as $val) {
      if($val instanceof UmiVarit) {
            echo "umi varit: ". $val->uvarJidlo(new ChlebaVeVajic­ku());
      }
}
 ?>

Interface můžete chápat jako svou vlastní kontrolu, kde si programátor označuje jednotlivé třídy podle toho, co mají umět. Myslím si, že úplnému pochopení, k čemu vlastně interface mohu využít a jak použít je otázkou praxe. Jak se říká: nic se nemá přehánět. A to platí i zde. Na druhou stranu, ignorace implementování rozhranní vede k chaosu a nižší funkčnosti.

Co se týče pravidel, jsou zde jasně danná specifika:
  • interface může obsahovat konstanty a veřejné metody
  • třída implementující interface musí obsahovat metody podle interface
  • třída může implementovat více rozhranní, které se oddělují čárkou (např. UmiVarit, PrepinaTelevizi)

Samotné PHP obsahuje několik předdefinovaných rozhranní, z nichž nejzajímavější je Iterator.

Tak by bylo k interface vše. Samozřejmě, dalo by se zde napsat spoustu dalších možností a využití, ale stačí, když si budu pamatovat, že Interface usnadňuje a označuje třídy tak, abych byl schopen použít jejich specifické vlastnosti.

Příště již ke zmíněným abstraktním třídám a dědičnosti, která je asi tím nejsložitějším tématem v OOP vůbec.

Leden 30th, 2007OOP v PHP 2 - základy

Minule jsem ukázal základní vlastnosti OO kódu. Dnes se pustím do bližší specifikace, základů psaní OO kódu.

Na začátku je dobré brát v potaz, že OO kód by měl být samodokumento­vatelný. To znamená, že kód je srozumitelný nejen pro počítač, ale také pro člověka. Pokud budu vycházet z tohoto základu, tak mi z toho vychází, že budu muset dodržovat základní principy při psaní OO kódu.

Začnu pěkne od začátku:

Třídy:

Název třídy se vždy uvádí velkým písmenem. Název třídy je podstatné jméno, nikoli sloveso. Pokud název třídy obsahuje více slov, používá se tzv. VelbloudiNotace.

Další důležitou roli hraje samotný název, který by neměl kolidovat s jiným názvem třídy. Ve skutečných OO jazycích je toto řešeno pomocí např. balíčků (packages) v Javě. Samotný balíček má i další vlastnosti, ale nám by stačilo, kdyby v PHP existoval alespoň v základní úrovni. Uvedu název balíčku, do kterého danná třída spadá a když budu potřebovat někde vytvořit objekt z této třídy, uvedu název třídy i s balíčkem. Název balíčku vlastně odpovídá adresářové struktuře, kde je má třída uložena (např. org.dostal.Za­mestnanci by bylo v adresáři /org/dostal/Za­mestnanci.clas­s). Krásné, že?

Bohužel PHP nic takového nemá. Proto je třeba volit jiný postup. Budeme vycházet z toho, že třídy vkládáme do vlastní adresářové struktury a tuto strukturu odvodíme pomocí názvu třídy. Jako oddělovač jsem zvolil „_“, což asi nejlépe odpovídá tomu, jak identifikovat strukturu, kde mám třídu uloženou.

Příklad: Vytvořím adresar „Model“, do něj vytvořím adresář „Table“. Poté vytvořím soubor s názvem „Filtr.php“. Nakonec do souboru vytvořím třídu „class Model_Table_Filtr {}“. Díky tomu jsem schopný identifikovat, kde třída „Filtr“ vlastně leží.

Další zásadou je, že jeden soubor = jedna třída. Nemá smysl o tomto polemizovat, je to způso, který se osvědčil nejenom v PHP.

Atributy tříd:

Atributy tříd by měly být vždy zapouzdřené, jinak řečeno, zvenku by k nim měl existovat pouze přístup přes setry a getry. Atribut třídy začíná malým písmenem a pokračuje opět velbloudí notací. Toto do začátku stačí.

Metody:

Název metody začíná vždy malým písmenem. Opět se využívá velbloudí notace. Název metody by mělo být sloveso (např. filtruj, zobraz, atd.), samozřejme to neplatí vždy. Metody začínající na set… jsou setry, nastavující nějakou hodnotu. Metody začínající na get… jsou getry, vracející nějakou hodnotu. Metody začínající na add… přidávají k nějaké hodnotě, další hodnotu. Metody načínající na is.. jsou kontrolní a vracejí Boolean (true, false) hodnotu. Metoda toString() vrací informaci o třídě. Existují další metody, tzv. magické metody začínající dvěma podržítkama, které proberu později. Jsou i jiné specifika, které teď nemá cenu rozebírat, pro začátek toto stačí.

I když jsou tyto informace dost nudné, jsou velice důležité pro další vývoj v objektově orientovaném programování.

Existuje spoustu doporučení a spousty standardů, čeho se držet, ale já vycházím z javovské konvence, která mi osobně přijde nejlepší.

Nyní opět malá ukázka toho, jak by měl vypadat standardní OO kód.

<?php
class Auto
{
    private $barva;
    private $rychlost = 0;

    public function __construct() {}

    public function setBarva($bar­va)
    {
        $this->barva = $barva;
    }

    public function getBarva()
    {
        return $this->barva;
    }

    public function setRychlost($rychlos­t)
    {
        $this->rychlost = (int) $rychlost;
    }

    public function getRychlost()
    {
        return $this->rychlost;
    }

    public function isRychlost()
    {
        return (boolean) $this->rychlost;
    }
}
 ?>
Příště už se pustím do samotného programování a proberu věci jako: typová kontrola, abstraktní třídy nebo interface.

Leden 29th, 2007OOP v PHP 1.

Spousta lidí tvrdí (stejně jako já), že psát objektově v PHP je šílenost a samotné PHP nemá tak dobrou podporu ani model k objektovému přístupu. Koncepce tohoto skriptovacího jazyka je postavena tak, abych byl schopen co nejrychleji nabastlit kód, který je schopen funkčního nasazení. Přesto je zde možnost psát objektově a od verze 5 dokonce i s vlastnostmi blížícími se objektově orientovaným jazykům typu Java či C++.

Předtím, než mohu začít psát objektově, musím mít elementární znalosti o tom, co jsou objekty, instance, jak funguje dědičnost, apod. Pokusím se zde popsat tyto znalosti tak, abych byl schopen na nich stavět.

Dost častá chyba je, když programátor pochopí OOP jako něco složitého či nereálného k použití. Ještě větší chybou je, když vývojář začne stavět projekt na objektech, aniž by měl dostatek znalostí k tomu, jak efektivně využít všech vlastností (toto byla i má chyba).

Takže o co vlastně jde? Na začátku můžete objekty chápat jako balíčky, které obsahují funkce a promenné, s kterými se dá pracovat v zájmu balíčku (objektu). Jinými slovy řečeno: „Objekty jsou obal nad procedurálním (obýčejným) kódem.“.

OOP obsahuje spoustu nového názvosloví, které je potřeba znát, abych byl schopen rozluštit, o čem se dva objektoví programátoři mluví :)

<?php
// toto je trida
class Zamestnanec
{
     // toto je atribut tridy
     private $cislo;

     // konstruktor tridy
     public function __construct() {}

     // metoda tridy
     public function setCislo($cis­lo)
     {
            $this->cislo = $cislo;
     }

     // metoda tridy
     public function getCislo()
     {
            return $this->cislo;
     }

}
 ?>

Pokud má třída metody začínající set či get, tak je nazývame jako setry a getry. Tyto setry a getry nastavují a vracejí hodnoty, respektive pracují s atributem třídy, který by se měl vždy definovat jako „private“.

Tímto jsem popsal základní názvosloví kolem třídy. V druhém kole popíši, jak třídu použiji.

<?php
$z = new Zamestnanec();
$z->setCislo(123);
echo $z->getCislo();
  

Takže, co je co? :) Promenná $z můžeme nazvat instancí objektu. Instance je jinak řečeno odkaz na objekt. Objekt je „new Zamestnanec()“. Někdo by si zde mohl myslet, že objekt poznám tak, že obsahuje „new“, ale není toúplně tak pravda. Např. objekt může být vytvářen jako jedináček (Singleton), který může být vytvořen pouze jednou. Takový objekt se vytváří interně a proto ho zvenku nevytvářím pomocí new (o tom, ale až později).

Dále je vidět, že pomocí instance (odkazu na objekt) volám metody set a get. Z vnějšku mohu volat pouze metody, které jsou public (veřejné). Důvody, proč je něco private, něco private a něco public, popíšu později.

To by bylo do začátku asi vše. Byli byste nyní schopni napsat třídu Auto obsahující atribut rychlost a metody na nastavení a vrácení rychlosti? Stejně tak i tuto třídu použít? ;)


© 2007 finc weblog | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress