[první draft (05/05/2004)]
komentujte a připomínkujte:
Tento dokument slouží jako referenční zdroj k ujasnění způsobu zápisu zdrojového kódu programů v jazyce PHP.
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.
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_.]+".
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.
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:
/index.php?zalozka=tech&sekce=tisk&id_clanku=13
versus /tech/tisk/?id_clanku=13) [pochopitelně, že ne
vždy je vhodné či možné řešit tento požadavek pevnou adresářovou
strukturou -- viz např. Apache: mod_rewrite]
Directory a jeho Allow from a Deny
from]
/konfigurace/ -- pro konfigurační soubory
(nejspíš jeden pro každou oblast nastavování či každý typ
uživatele) s definicemi globálních konstant a proměnných;
patří sem nejspíš taktéž něco jako init.php s
celou sadou potřebných "include" příkazů pro všechny knihovny
/knihovny/ -- pro uzavřené re-use komponenty,
které se ve shodném tvaru mohou nacházet v různých projektech
(např.: db.php, auth.php,
sablona.php, debug.php,
fnc.php, soap.php, ...)/sablony//obrazky//styly//admin//data//upload/
Rozhodně si nakonec celá navržená a zavedená adresářová struktura
zaslouží komentář v samostatném souboru umístěném v
DocumentRoot.
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.
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.
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."]";
}
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);
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;
}
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);
}
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.
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ů:
@author@deprecated@example@global@param@return@see@since@todo@version
<?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;
}
...
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.)
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) {
...
}
Jako anonymní (bez jiného významu) indexy (parametry) for
cyklů užívejte proměnné $i, $j a $k.
Vždy používejte jednotné uvození bloků složenými závorkami. Neužívejte
alternativní syntax řídicích struktur endif,
endwhile nebo endfor.
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");
}
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;
}
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";