Lekce 14 - Nejčastější chyby PHP nováčků - Umíš pojmenovat proměnné?
V předešlém cvičení, Řešené úlohy k 13. lekci PHP, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
V dnešním PHP tutoriálu si ukážeme první tzv. dobré praktiky pro programování v PHP. Často je porušují nejen nováčci a programátoři tak zanášejí do svých programů zbytečné chyby. Neděláš je také?
Slovo senior programátora

Gratuluji ke zdolání prvních lekcí Základních konstrukcí jazyka PHP!
Materiál pro dnešní lekci jsem sestavil na základě dvaceti let zkušeností s programováním. Jako šéfredaktorovi a lektorovi mi rukama prošly stovky, možná tisíce zdrojových kódů vytvořených komunitou. Nebylo těžké si všimnout, že ačkoli většina těchto kódů funguje, obsahuje zbytečné chyby, které se navíc stále dokola opakují. Chyby kupodivu často dělali jak nováčci, tak zkušenější programátoři. Mezi chybující jsem v začátcích patřil i já.
Došel jsem k tomu, že základním a mylným předpokladem je:
✗ Program je správně, pokud funguje.
Programy a domy
Pokud stavíme dům, tak to, že se nám líbí a nefouká do něj, neznamená, že je zkonstruovaný správně. Dům totiž musí mít promyšlenou architekturu, a pokud nemá základy, za pár let se nám začne sesouvat.
Programování je často přirovnáváno ke stavebnictví právě s ohledem na architekturu, v našem případě ovšem tu softwarovou. Vysvětleme si proč.
Lidský mozek dokáže najednou pracovat jen s určitým omezeným množstvím informací. Zjednodušeně můžeme říci, že pokud je program napsaný nepřehledně, od určité chvíle by musel programátor udržet v hlavě více věcí, než člověk vůbec dokáže. Přidávání dalších funkcí do takového programu pak vždy způsobí, že v aplikaci vznikne chyba. V praxi to dopadá tak, že hobby projekt autora "přestane bavit" a komerční projekt zkrachuje, protože už je "moc složitý".
Uveďme si ještě jiný příklad. Když bude naše domácnost uspořádaná tak, že kladivo bude v lékárničce, která bude umístěna ve sklepě, asi těžko s ní budeme schopní efektivně fungovat. Ačkoli tento příklad zní absurdně, jeho alternativy v podobě programů vznikají denně.
Kdy je program správně?
To je snadné. Program je správně, pokud:
- funguje,
- dodržuje dobré praktiky a
- je otestovaný.
Všimněme si, že funkcionalita z pohledu uživatele programu představuje jen 1/3 kritérií kvality programu. Podobně jako funkčnost domu z pohledu bydlícího představuje asi jen zlomek jeho reálné kvality z hlediska stavařiny.
Právě o porušování dobrých praktik a o kvalitě kódu se dnes budeme bavit. Záleží nám na tom, abyste byli opravdu dobří, proto těchto lekcí naleznete napříč našimi kurzy vícero.
Jak správně pojmenovávat proměnné?
Říká se, že 10 % času něco programujeme a 90 % času pro to
vymýšlíme název Jedná se
samozřejmě o nadsázku, nicméně vtip naráží na nutnost strávit určitý
čas vymýšlením názvů proměnných. To aby každý včetně nás, kdo se po
pár měsících vrací k vlastnímu kódu, pochopil, k čemu ona proměnná
slouží. Obecně se dá spolehnout na jednoduché pravidlo:
Proměnné vždy pojmenováváme podle toho, co obsahují, nikoli podle toho, k čemu v programu slouží.
Porovnejme následující dva kódy:
✗ Špatně
$vypis = $_GET['n']; $text2 = "Jan Novák"; $pole = []; $foo = 0; $vypocet = 0;
✓ Správně
$nazev = $_GET['n']; $jmeno = "Jan Novák"; $odpovedi = []; $bonus = 0; $celkovyBonus = 0;
Oba kódy vytvářejí proměnné pro jednoduchý kvíz. U prvního příkladu není vůbec jasné, co některé proměnné obsahují.
Častou chybou také je, že chceme např. uložit výsledek
nějakého výpočtu a proměnnou pojmenujeme
$vypocet
. Výpočet s proměnnou ovšem vůbec nesouvisí, to je
nějaká akce (děj), proměnná vždy obsahuje
hodnotu (výsledek děje). Tou je zde v případě kvízu
$celkovyBonus
. Podobně je v prvním kódu pojmenovaná proměnná
$vypis
, protože ji někde vypisujeme. Z druhého kódu ale
reálně vidíme, že obsahuje název kvízu.
Ruku na srdce – kdo z vás by pochopil, že kód vlevo se týká programu na kvízy?
Proměnné také nikdy nepojmenováváme
$pomocna
nebo $pom
apod.
Pojmenování polí
Pojmenování polí je jedním z největších kamenů úrazu v programování. Existuje jednoduché pravidlo:
Kolekce vždy pojmenováváme v množném čísle.
Opět tím samozřejmě následujeme poučku, že název proměnné je odvozený od toho, co je v proměnné uložené. Je-li v ní uloženo více věcí, měl by být také název logicky v množném čísle.
Ukažme si pár chybných a správných příkladů deklarace polí:
✗ Špatně
$arr1 = [40000, 50000, 60000]; $arr2 = [80000, 100000, 120000]; $uzivatel = ['pepa', 'karel']; $cisla = [40000, 50000, 60000]; $vek = [81, 25, 11, 45]; $pole = [true, true, false]; $novePole = [true, false, false];
✓ Správně
$platyVstup = [40000, 50000, 60000]; $platyVystup = [80000, 100000, 120000]; $uzivatele = ['pepa', 'karel']; $platy = [40000, 50000, 60000]; $veky = [81, 25, 11, 45]; $odpovedi = [true, true, false]; $opraveneOdpovedi = [true, false, false];
Vyhneme se zavádějícím názvům jako $cisla
, to už můžeme
opět rovnou napsat $promenne
. Snad nemusíme ani zmiňovat, že
pole určitě nepojmenujeme $pole
Podle toho, co je uvnitř opravdu
uloženo, zvolíme jako název např.
$platy
,
$odpovedi
apod.
Zvláště pak pojmenování pole $arr
jsem osobně viděl snad
milionkrát. Vždy je pak nutné chvíli rolovat zdrojovým kódem, aby člověk
zjistil, co v poli vlastně je. Pokud je takovýchto názvů plná celá
aplikace, člověk ztrácí čas, koncentraci a dělá chyby.
Pozor na "czenglish" a diakritiku
Ve zdrojovém kódu je na naší úrovni začátečníků jedno, jakým jazykem budeme proměnné pojmenovávat (pokud tedy nepošleme Angličanovi kód v češtině).
Proměnné v jednom projektu pojmenováváme jedním jazykem. Pokud pojmenováváme česky, tak bez diakritiky!
Opět si ukažme příklady:
✗ Špatně
$zpráva = "Čau!"; $count = 0;
✓ Správně
$zprava = "Čau!"; $pocet = 0;
Nebo:
$message = "Čau!"; $count = 0;
V identifikátorech (např. v názvech proměnných) nikdy nepoužíváme háčky a čárky. V hodnotách v nich uložených je to již samozřejmě v pořádku.
Přestože moderní jazyky podporují kódování UTF-8 i v identifikátorech, na háček nebo čárku lze velmi snadno zapomenout a používáme pak jinou proměnnou! Navíc soubor se zdrojovým kódem může zpracovávat aplikace, která kódování UTF-8 nepodporuje, a typicky se to i časem stane (např. je občas problém zobrazit diakritiku v příloze mailovým klientem apod.).
Víceslovné proměnné
Dnešní aplikace jsou stále složitější. Často se stane, že by jedno
slovo k popisu toho, co je v proměnné uloženo, nestačilo. Pak je výhodné
použít více slov. Krátké identifikátory z 80. let tak v současných
business aplikacích střídají i poměrně dlouhé názvy jako
$userObjectOutputStreamFactory
a podobně.
Takto dlouhý název má ovšem smysl jen ve složité
aplikaci, kde je několik podobných proměnných, a proto musíme přidat
další slovo. V Hello world aplikaci tedy nebudeme vytvářet proměnnou
$textSPozdravemHelloWorld
, ale stačí nám jen
$pozdrav
, pokud tam jiný není
Oddělení slov
Kvůli čitelnosti musíme slova v takovém názvu proměnné nějak oddělit. Více slov oddělujeme podle konvence daného programovacího jazyka. Ty jsou v PHP dva a zjednodušeně řečeno záleží na tom, zda programujeme:
- objektově – tehdy používáme tzv.
camelCase
(česky velbloudí notace, kdy každé další slovo má velké písmeno a název pak vypadá jako hrby). Tuto konvenci budeme používat i my v kurzu, protože brzy začneme programovat objektově, což je způsob, kterým se dnes vytvářejí moderní projekty. Pro konstanty ovšem používáme velká písmenaSNAKE_CASE
. - procedurálně – pro neobjektové projekty se zpravidla
používá
snake_case
, kdy slova oddělujeme podtržítkem.
PHP samotné má pro velkou část své funkcionality i dva způsoby volání – buď přes třídy, kde je vše pojmenované camelCasem, nebo přes funkce používající k oddělení slov podtržítka. To aby PHP stále podporovalo starší neobjektové projekty (za všechny si uveďme WordPress, na kterém běží půl miliardy webových stránek). PHP konvencím je také věnován celý kurz Standardy jazyka PHP.
Vyhneme se pokud možno číslování proměnných a už vůbec nepíšeme
čísla slovy, ne $pozdrav2
ani $pozdravDve
. "Dvě"
totiž neříká nic o tom, co pozdrav obsahuje.
Ukažme si to na příkladech:
✗ Špatně
$zprava1 = 'Ahoj'; $zpravaDve = 'No nazdar'; define('minimalniVek', 18);
Zde není jasné, co je uloženo:
$prijato = $_GET['z']; // text, bajty, zprava, objednavka…? $odeslano = 'No nazdar'; define('minimalni_vek', 18);
A zde je název nečitelný:
$prijatazprava = 'Ahoj' $odeslanazprava = 'No nazdar'; define('MINIMALNIVEK', 18);
✓ Správně
$prijataZprava = 'Ahoj'; $odeslanaZprava = 'Rád tě vidím'; define('MINIMALNI_VEK', 18);
Nebo pro neobjektové projekty:
$prijata_zprava = 'Ahoj'; $odeslana_zprava = 'Rád tě vidím'; define('MINIMALNI_VEK', 18);
Zmíněné dva správné styly pojmenování proměnných v jednom projektu nikdy nemícháme.
Nepoužíváme zkratky
Tuto podkapitolu započněme citací:
Všichni si lámali hlavu nad tím, k čemu je ten sloupec
DATNAR
. Až se jednou zjistilo, že je to prý datum narození.
Tato špatná praktika je vlastně opakem víceslovných názvů
proměnných. Nevymýšlíme nesmyslné zkratky. Například z názvu
$pz
nikdo nepozná, že myslíme $prijataZprava
.
Pomůcka může být:
Pokud se na kód podívá někdo jiný než my, měl by přesně vědět, co ve které proměnné je.
✗ Špatně
$zp = 'Ano'; $pz = 5;
✓ Správně
$zprava = 'Ano'; $pocetZprav = 5;
Některé starší PHP funkce jsou pojmenované právě pomocí
zkratek. Zkuste si schválně tipnout, co asi dělá strrchr()
Tuto konvenci PHP rychle
opustilo, ale z důvodu zpětné kompatibility ji tu a tam ještě potkáme.
Tento neduh je daň za to, že je tu s námi PHP už tak dlouho. Výhodou naopak
je, že na něm běží většina internetu.
Jak jsme slíbili, k tématu dobrých praktik se ještě několikrát
vrátíme v podobných, spíše odpočinkových lekcích
V příští lekci, Funkce pro práci s řetězci v PHP, si vyzkoušíme několik funkcí pro práci s textovými řetězci.