Honck [www.amler.biz]

Coding standard pro PHP

[první draft (05/05/2004)]

komentujte a připomínkujte:

1 Úvod

1.1 Účel dokumentu

Tento dokument slouží jako referenční zdroj k ujasnění způsobu zápisu zdrojového kódu programů v jazyce PHP.

1.2 Důvod vzniku dokumentu

Potřeba jednotného způsobu zápisu zdrojových kódů vzniká v okamžiku, kdy se na vývoji jednoho softwarového produktu podílí více lidí. Efektivní zásahy do kódu předpokládají snadnou orientaci, přehlednost a jednotný styl strukturování. Přesně stanovený postup kódování taktéž umožňuje sdílet a znovupoužívat hotové knihovny.

2 Organizace souborů

2.1 Jména

Jména souborů by měla obsahovat pouze malá písmena anglické abecedy, podtržítko nebo tečku a nic jiného. Toto pravidlo je vyjádřitelné regulárním výrazem "[a-z_.]+".

2.2 Koncovky

Soubory s jakýmkoliv PHP kódem (ať už je to libovolná aplikační část či pouhá šablona) by měly mít koncovku jedině php. Jakékoli jiné (inc, class, phtml, ...) mohou představovat potenciální bezpečnostní riziko.

2.3 Adresářová struktura

Struktura adresářů by měla být promyšlena před začátkem kódování. Měla by vycházet z návrhu aplikace. Speciálně se zamyslete nad:

Rozhodně si nakonec celá navržená a zavedená adresářová struktura zaslouží komentář v samostatném souboru umístěném v DocumentRoot.

2.4 Oddělení aplikační a prezentační logiky

Přísná separace výkonného kódu (aplikační logika) od kódu generujícího vzhled stránky (šablony), či obecně jakýkoli druh výstupu, má své opodstatnění. Výhodou je především možnost úpravy vzhledu stránek bez nutnosti zasahovat do aplikační části, mohou to dokonce dělat různé osoby. Rozhodně se od sebe diametrálně odlišují činnosti jako sestavení SQL dotazu a ukončení tagu <div>. Další nespornou výhodou je možnost pouhou záměnou šablon vytvářet naprosto odlišný druh výstupu (nejen HTML, ale např. i XML, PDF, TeX, XLS, etc.).

Obecně výkonný kód vypadá tak, že v rámci jednoho souboru je jediné <?php (na úplném začátku) a jediné ?> (na úplném konci), tj. negeneruje žádný výstup přímo, pouze ho řídí pomocí nějaké vhodné třídy či knihovních funkcí. Šablona se potom naopak snaží minimalizovat množství PHP kódu (např. konstrukcí <?=$promenna?> a maximálně jednořádkovými vstupy řídicích konstrukcí) a řídí vzhled výstupu.

3 Sazba

3.1 Délka řádku

V rámci čitelnosti zdrojových kódů by měla být délka řádky omezena 80 znaky. Důvodem je viditelnost celého řádku bez horizontálního posuvu na všech terminálech.

3.2 Odsazování řádků

Každou úroveň zanoření odsazujte 4 mezerami.


         if (!isset($adr_kod)) { 
             $xpath = "/stat/kraj/okres/obec";
             if (!empty($adr_obec)) {
                 $xpath .= "[starts-with(@nazev, '".$adr_obec."')]";      
             }
         } else {
             $xpath = "/stat/kraj/okres/obec/adresa[@kod=".$adr_kod."]";
         }
      

3.3 Zalamování řádků

Je-li výraz příliš dlouhý než aby se vešel na řádku, zalamujte v duchu těchto pravidel:


      vypocitej_neco($neco + ($neco / $neco_hodne_dlouheho) + 50
                     + ($dalsi_dlouhy_deleny_scitanec / 30),
                     $druhy_parametr);
      

3.4 Bílé znaky

Klíčová slova od následující závorky oddělujte mezerou, funkce by naopak měly být závorkou těsně následovány. Před a za znak přiřazení, logický či aritmetický operátor vložte mezeru.


        if (($neco > KONSTANTA) || ($neco == MAX_HODNOTA)) {
            $vysledek = ($neco + 1) / 20;
            $retezec .= "vysledek: ".$vysledek;
        }
      

3.5 Použití složených závorek

Jsou dva přípustné způsoby zápisu složených závorek ohraničujících blok. Buďto závorky na nové řádce a pod sebou:


        if ($neco > KONSTANTA)   
        {
            vypocitej_neco($neco);
        }       
        else
        {
            vypocitej_neco($neco + KONSTANTA);
        }
      

nebo začíná na stejné řádce a končí pod uvozením bloku:


        if ($neco > KONSTANTA) {
            vypocitej_neco($neco);
        } else {
            vypocitej_neco($neco + KONSTANTA);
        }
      

4 Komentáře

Skutečná dokumentace programu je v jeho komentářích. Snahou při psaní komentářů by mělo být "převyprávět příběh" programu.

Neužívejte komentáře shellového typu (#). Užívejte pouze /* ... */ pro víceřádkové a dokumentační komentáře a // ... pro jednořádkové.

Komentujte hojně, výstižně a slušně (nikdy nevíte kdo kdy bude prohlížet vaše zdrojové kódy nebo je uvidí náhodou). V nedokumentačních komentářích uvozujte "todo" sekce třemi vykřičníky, případně otazníky. Rozhodně komentujte části kódu, o kterých víte, že mají slabiny, jsou neprůhledné nebo dokonce, že je jisté, že je bude potřeba přepsat.

4.1 Dokumentační komentáře

Pro zápis komentářů používejte styl podle programu phpDocumentor (je obdobný jako v javadoc). Tento program potom sám generuje dokumentaci (do HTML, v komentářích lze používat HTML tagy) ze správně zapsaných dokumentačních komentářů. Každý soubor by měl začínat komentářem a určitě pak každá funkce a třída.

Přehled důležitých dokumentačních tagů:


   <?php
       /**
        * Souprava obecnych funkci.
        *
        * @author  Jan Amler <jan@radsinickvulispamu.biz>
        * @version 3.2 ke dni 21.2.2004
        */

       /**
        * Funkce preklada text do jeho podoby v HTML entitach. Casty zpusob
        * pasivni ochrany emailu pred roboty, kteri ho zarazuji do spam-listu.
        * 
        * @param  string $email     email (ci libovolny text) k prekladu do entit 
        * @return string            entitami escapovany email
        *
        * @see    nejaka_nase_fce() funkce co by nejak souvisela
        * @since  verze 2.71
        * @author Nekdo Jiny <nekdo@jiny.cz>
        * @todo   Mozna doplnit stridani dekadickych (ord) entit s hexadecimalnimi
        *         (bin2hex). Ovsem napriklad MSIE4 hexa entity neumi.
        */
       function zakoduj_email($email) {
           $vysledek = "";              // neslo by to elegantneji: ???
           for ($i = 0; $i < strlen($email); $i++) { 
               $vysledek .= "&#".ord($email[$i]).";";  // taky nejak bin2hex   !!!
           }
           return $vysledek;
       }

    ...
    

5 Konvence pojmenování identifikátorů

5.1 Čeština

Při pojmenovávání identifikátorů volte české (resp. "ceske") názvy. Výhoda spočívá v rozeznání, co je naše vlastní a co je integritní součástí jazyka, na první pohled. (Nevýhodou zůstává nižší znovupoužitelnost [reusability] vůči nečeskému světu.)

5.2 Konstanty, třídy, metody, funkce, proměnné

Konstanty zapisujte velkými písmeny, slova oddělujte podtržítkem (regulární výraz: [A-Z_]+).

V rámci objektového programování používejte konvence Javy, tj. pro názvy tříd velké první písmeno, ostatní malá, první písmena slov opět velkými; pro názvy metod (ne konstruktorů, ty jsou stejné jako názvy tříd) a proměnných všechny malé, jen začátky slov velkými písmeny.

Mimo třídy a uvnitř jejich metod zapisujte proměnné v duchu jazyka C, tj. všechny písmena malá, slova oddělená podtržítkem.

Názvy tříd a proměnných by měly pojmenovávat nějaký objekt (tj. např. $nazev_ulice nebo $cislo_domu), naproti tomu názvy funkcí by měly pojmenovávat nějakou činnost (tj. např. vypis_nazev() nebo formatuj_ico()).


        define ("KONSTANTA"   ,   10);
        define ("MAX_HODNOTA" , 1000);

        ...

        class Trida extends JinaTrida {
            var $atribut;
            var $dalsiAtributTridy;

            function Trida($neco) {  // konstruktor
                $this->atribut = $neco;
            }

            function metodaTridy() {
                ...    
            }
        }

        ...

        $promenna       = MAX_HODNOTA;
        $bezna_promenna = KONSTANTA;

        function bezna_funkce($neco) {
            ...
        }
      

5.3 Zažité užití názvů identifikátorů

Jako anonymní (bez jiného významu) indexy (parametry) for cyklů užívejte proměnné $i, $j a $k.

6 Řídicí struktury

Vždy používejte jednotné uvození bloků složenými závorkami. Neužívejte alternativní syntax řídicích struktur endif, endwhile nebo endfor.

6.1 if -- else

Podmíněný blok vždy ohraničte složenými závorky, i když obsahuje pouze jediný příkaz. Nepoužívejte zastaralou a zbytečnou konstrukci elseif, místo ní lze vždy napsat else if.


        if ($neco < KONSTANTA) {
            proved_jediny_prikaz($neco);
        } else if ($neco == KONSTANTA) {
            otestuj_vstup($vstup);        
            vypocitej_neco($neco);
        } else {
            ohlas_chybu ("musi byt mensi nebo rovno");
        }
      

6.2 switch

Pokud upotřebíte "fall-through" efekt (tj. nepoužijete pro nějakou větev break), vždy ho opatřte komentářem. Každý switch příkaz by měl mít default větev.


        switch ($promenna) {
            case 10:
                $nastaveni["neceho"] = true;
                // FALLS THROUGH !!!
            case 20:
                $cislo_domu++;
                break;
            default:
                generuj_chybu("neznamy stav");
                break;
        }
      

7 Různé

Indexy pole typu string vždy uvádějte v uvozovkách.

Při skládání částí řetězce s proměnnými je vhodné pro každou proměnnou řetězec přerušit, obzvláště pro pole.


      $retezec = "datum :".$datum["den"]."/".$datum["mesic"]."/".$datum["rok"];
    

Klíčová slova SQL dotazů pište velkými písmeny.


      $dotaz = "SELECT * FROM moje_tabulka WHERE id = 1";