Manual:Coding conventions/PHP/cs

Tato stránka popisuje konvence které se používají při psaní u PHP skriptů v. Viz také, které platí pro všechny programovací jazyky včetně PHP. Pokud byste chtěli krátký kontrolní seznam, který vám pomůže zkontrolovat vaši tvorbu, zkuste použít.

Aby mohli vývojáři snadno odhalit kód, který není v souladu s touto konvencí, existuje nástroj stylize, který kontroluje syntaxi a doplní mezery na příslušná místa. Tento nástroj je dostupný přes webové rozhraní. Doporučuje se jej spustit přes soubory odevzdané Gitu.

Jsou také k dispozici pravidla pro PHP_CodeSniffer. Další podrobnosti najdete na. Repozitář git  obsahuje nastavení PHP_CodeSniffer pro kód MediaWiki.

Mezery
Pro MediaWiki je prvořadým úkolem srozumitelnost a přehlednost kódu. Proto se při psaní hojně využívají mezery.

Odsazení provádějte tabulátory, nikoli mezerami. Omezte řádky na 120 znaků (při šířce tabulátoru 4 znaky).

U binárních operátorů, přidejte z každé strany jednu mezeru, tak aby byly naprosto jasně odděleny. Viz příklad:

Uvnitř umístěte mezery vedle závorek, kromě případů, kdy jsou závorky prázdné. Za názvem funkce nevkládejte mezeru.

Vložte mezeru za  v nápovědě k návratovému typu funkce, ale ne před:

Mezeru do závorek vložte jen pokud chcete deklarovat pole, které nemá být prázdné. Mezery také nepoužívejte při adresování jednotlivých prvků pole.

Za řídící prvky, jako je, , , , nebo klíčové slovo  naopak mezeru vložte vždy:

U deklarování typu proměnné nepoužívejte nikdy mezery. Ani v závorkách, ani za nimi:

U komentářů přidejte mezeru za nebo  a teprve pak napište svůj komentář.

Jako vývojářskou pomůcku, která se postará o správné umístění mezer, lze použít nástroj stylize, který přidává mezery automaticky podle konvence PHP. Nástroj je dostupný přes webové rozhraní.

Ternární operátor
může být velice užitečný, pokud jsou výrazy velmi krátké a zřejmé:

Pokud však uvažujete o víceřádkovém výrazu s ternárním operátorem, zvažte místo toho použití bloku. Pamatujte, že místo na disku je levné, čitelnost kódu je všechno, "if" je angličtina a " " ne. Pokud používáte víceřádkový ternární výraz, otazník a dvojtečka by měly být na začátku druhého a třetího řádku a nikoli na konci prvního a druhého (na rozdíl od konvence JavaScriptu MediaWiki).

Protože MediaWiki vyžaduje PHP (MW stabilní php požadavek) nebo novější, je použití shorthand ternárního operátora  známého také jako elvis operator, zavedeného v PHP 5.3, povoleno.

Od PHP 7.0 je k dispozici null coalescing operator (nulový koalescenční operátor) a v některých případech může nahradit ternárního operátora. Například místo  byste mohli napsat:

Literální řetězce
Jednotlivé uvozovky jsou preferovány ve všech případech, kdy jsou rovnocenné dvojitým uvozovkám. Kód používající jednoduché uvozovky je méně náchylný k chybám a snadněji se kontroluje, protože nemůže náhodně obsahovat únikové sekvence (escape sequences) nebo proměnné (variables). Například regulární výraz vyžaduje dodatečné zpětné lomítko, takže je o něco víc složitější a náchylnější k chybám než. Také pro lidi, kteří používají US/UK qwerty klávesnice, je snazší jej psát, protože není nutné mačkat Shift.

Nebojte se však použít funkci PHP interpolace do dvojitých uvozovek:

To má o něco lepší výkonové vlastnosti než ekvivalent pomocí operátoru zřetězení (tečka) a také to lépe vypadá.

Řetězce ve stylu heredoc jsou také někdy užitečné:

Někteří autoři rádi používají END jako koncový token, který je také názvem funkce PHP.

Funkce a jejich parametry
Vyhněte se předávání velkého počtu parametrů funkcím nebo konstrukcím:

Je nemožné rychle si zapamatovat pořadí parametrů a nevyhnutelně skončíte s nutností zakódovat všechna výchozí nastavení u volajících, abyste si přizpůsobili parametr na konci seznamu. Pokud vás láká kódovat takovou funkci, zvažte místo toho předání asociativního pole pojmenovaných parametrů.

Obecně se nedoporučuje ve funkcích používání booleovských parametrů. V případě, bez vyhledání dokumentace pro , je nemožné vědět, co mají tyto parametry označovat. Mnohem lepší je buď použít konstanty třídy a vytvořit obecný parametr příznaku:



Nebo, aby vaše funkce akceptovala řadu pojmenovaných parametrů:



Zkuste nepřepočítávat proměnné v průběhu funkce a vyhýbejte se úpravám parametrů předávaných funkci (pokud nejsou předány odkazem a to je samozřejmě smyslem celé funkce).

Výrazy přiřazení
Použití přiřazení jako výrazu je pro čtenáře překvapivé a vypadá to jako chyba. Nepište kód takto:

Prostor je levný a vy jste rychlý písař, takže místo toho použijte:

Použití přiřazení v klauzuli bývalo pro iteraci legitimní:

V novém kódu to není nutné. Místo toho použijte:

Výpůjčky z jazyka C
PHP je programovací jazyk, který byl navržen lidmi, kteří milovali programování v jazyce C a proto chtěli do PHP implementovat takovou syntaxi, na jakou byli zvyklí. Ovšem PHP se v několika významných detailech od jazyka C liší.

U jazyka C se konstanty implementují jako makra pro preprocesor a tím pádem se zpracovávají velmi rychle. U PHP, se ale vyhledává jméno konstanty v indexované tabulce což je mnohem pomalejší, než když se použije řetězcový literál. Ve většině případů, tam, kde byste použili v jazyce C množinu maker, je u PHP výhodnější použít řetězcové literály. U PHP, se ale vyhledává jméno konstanty v indexované tabulce což je mnohem pomalejší, než když se použije řetězcový literál. Ve většině případů, tam, kde byste použili v jazyce C množinu maker, je u PHP výhodnější použít řetězcové literály.

PHP má tři speciální literály, pro které je velká, či malá nebo smíšená velikost písma v jazyce nevýznamná (od PHP 5.1.3), ale pro kterou je naše konvence vždy malá:, a.

Použijte, nikoli. Mají jemně odlišný význam:

Ovšem z hlediska výkonu na tom bude druhá varianta hůř.

Alternativní syntaxe pro řídící struktury
PHP umožňuje pro řídicí struktury, jako,  , atp., používat alternativní syntaxi, při které se místo složených závorek použije dvojtečka:

Takovéto syntaxi byste se měli vyhnout velikým obloukem, protože řada textových editorů by se zobrazením takového kódu mohla mít problém. Takže raději použijte složené závorky:

Závorky
Více o závorkách najdete v části o odsazování a zarovnávání kódu na stránce věnované všeobecné konvenci pro psaní zdrojového kódu.

Deklarování typů v parametrech funkce
Pokud je to možné, použijte [deklarace typu https://php.net/functions.arguments#functions.arguments.type-declaration] a [deklarace typu návratu https://php.net/functions.returning-values#functions.returning-values.type-declaration] (tipování typu).

Upozorňuji, že u starších verzí PHP (před 7.4), nelze obsloužit naznačování typu (ať již restriktivní, či volné) v rámci podtřídy.

Scalar typehints are allowed as of MediaWiki 1.35, following the switch to PHP 7.2 (T231710).

Use PHP 7.1 syntax for nullable parameters: choose

instead of

The former conveys precisely the nullability of a parameter, without risking any ambiguity with optional parameters. IDEs and static analysis tools will also recognize it as such, and will not complain if a non-nullable parameter follows a nullable one.

Konvence pro jména
Pro názvy funkcí a proměnných používejte notaci lower-CamelCase. Jak ukazuje příklad:

Pro názvy tříd používejte naopak Upper-CamelCase:. Použijte velká písmena s podtržítky pro globální konstanty a konstanty tříd:,. Jiné proměnné jsou obvykle malými písmeny (lowercase) nebo lowerCamelCase. Nepoužívejte podtržítka v názvech proměnných.

Používejte také zavedené prefixy. I ty napovídají oč v kódu jde:

Funkce

 * (wiki funkce) – funkce, dostupné na té nejvyšší úrovni, např.
 * (funkce rozšíření) = jsou globální funkce, napsané v rámci rozšíření. I když "většina skriptů napsaných v moderním stylu vkládá do svých tříd funkce, které se registrují jako háčky, jako statické metody třídy, aby na té nejvyšší úrovni do budoucna zbylo jen minimum, takto pojmenovaného kódu." (-- brion in Manual_talk:Coding_conventions)

V tomto případě se preferují slovesa, která jasně naznačí co má funkce udělat: Takže místo použijte.

Proměnné

 * – globální proměnné, např. . Vždy to používejte pro nové globální, aby bylo snadné najít chybějící deklarace "". V rozšířeních by měl být název přípony použit jako oddělovač oboru názvů. Například a ne.
 * Globální prohlášení by měla být na začátku funkce, takže závislosti lze určit bez nutnosti číst celou funkci.

Je běžné pracovat s instancí třídy databáze. Máme pro ně konvenci pojmenování, která pomáhá sledovat povahu serveru, ke kterému jsme připojeni. Toto je obzvláště důležité v replikovaných prostředích, jako jsou Wikimedie a další velké wiki. Ve vývojových prostředích obvykle neexistuje žádný rozdíl mezi těmito dvěma typy, které mohou skrývat jemné odlišnosti.


 * – objekt  pro zápis (primární připojení)
 * – objekt  pro čtení, které není citlivé na souběžnost (může to být replika pouze pro čtení, mírně za primárním stavem, takže se nikdy nesnažte s ním zapisovat do databáze nebo získat "autoritativní" odpověď na důležité dotazy, jako jsou oprávnění a stav bloku)

Ve starém kódu lze vidět následující, ale v novém kódu se to nedoporučuje:


 * – proměnné relace, např.
 * – proměnné souborů cookie, např.
 * – proměnné příspěvku (odeslané prostřednictvím polí formuláře), např.
 * – proměnné členů objektu: . To je v novém kódu odrazováno, ale zkuste zůstat v rámci třídy konzistentní.

Funkce by měla být použita, pouze pokud chcete potlačit chyby. Jinak stačí použít  (booleovský převod).

Obecný případ použití: Volitelné booleovské konfigurační klíče, které mají výchozí hodnotu false.
 * essentially does.
 * Dejte si pozor na booleovské konverze.
 * Potlačuje chyby ohledně nedefinovaných vlastností a proměnných. Pokud chcete testovat pouze nedefinované, použijte . Pokud máte v úmyslu pouze otestovat "prázdné" hodnoty (např. false, zero, empty array, atd.), použijte.

Nepoužívejte k testování. Použití v této situaci může způsobit chyby skrytím chybně napsaných názvů proměnných. Místo toho použijte.

Booleovská konverze

 * Nepoužívejte  nebo  k testování, zda je řetězec nebo pole prázdný, protože PHP považuje   za falešné - ale   je platný název a platné uživatelské jméno na MediaWiki. Místo toho použijte   nebo.
 * Prostudujte si pravidla pro převod na booleovský výraz. Při přeměně řetězců na boolean buďte opatrní.

Ostatní

 * Array plus nečísluje klíče numericky indexovaných polí, takže . Pokud chcete, aby klíče byly přečíslovány, použijte :
 * Ujistěte se, že jste nastavili na  . Toto vás upozorní na nedefinované proměnné a další jemné gotchas, které bude PHP ignorovat. Viz též.
 * Při práci v čistě PHP souboru (např. ne v HTML šabloně) vynechejte koncové tagy . Tyto značky často způsobují problémy s koncovými mezerami a chybovými zprávami "záhlaví již odeslány" (headers already sent) (srovnání viz.  17642 a http://news.php.net/php.general/280796). V řízení verzí je běžné, že soubory mají na konci souboru nový řádek (který editoři mohou přidat automaticky), což by tuto chybu vyvolalo.
 * Nepoužívejte syntaxi zavedenou v 5.3. PHP možná zavedlo tuto funkci, ale to neznamená, že bychom ji měli používat.
 * Pokud nemusíte, neprovádějte odkaz při procházení pole. I tehdy si uvědomte možné důsledky. (viz https://www.intracto.com/en-be/blog/php-quirks-passing-an-array-by-reference/)
 * PHP umožňuje deklarovat statické proměnné i v rámci nestatické metody třídy. To v některých případech vedlo k drobným chybám, protože proměnné jsou sdíleny mezi instancemi. Pokud byste nepoužili vlastnost, nepoužívejte ani statickou proměnnou.

Operátory rovnosti
Buďte opatrní s operátory porovnávání dvojitého rovná se (double-equals comparison operators). Trojité rovná se je obecně intuitivnější a mělo by být upřednostňováno, pokud nemáte důvod k použití dvojitých rovná se.


 * je pravda (!)
 * je pravda (!)
 * je nepravdivý
 * Chcete-li zkontrolovat, zda jsou dva skaláry, které mají být číselné, stejné, použijte, např.  je pravda.
 * Chcete-li zkontrolovat, zda jsou dvě proměnné typu 'řetězec' a mají stejnou posloupnost znaků, použijte, například  je nepravda.

Watch out for internal functions and constructs that use weak comparisons; for instance, provide the third parameter to, and don't mix scalar types in   constructs.

Do not use Yoda conditionals.

Přesnost čísla JSON
JSON používá systém typu JavaScriptu, takže všechna čísla jsou reprezentována jako 64bitová čísla IEEE s pohyblivou řádovou čárkou. To znamená, že čísla ztrácejí přesnost, když se zvětšují, a to do té míry, že některá celá čísla jsou nerozeznatelná: Čísla nad 2^52 budou mít přesnost horší než ±0,5. Takže velké celé číslo se může nakonec změnit na jiné celé číslo. Chcete-li se tomuto problému vyhnout, řešte potenciálně velká celá čísla jako řetězce v JSON.

Nepoužívejte vestavěnou serializaci
Integrovaný mechanismus serializace PHP (funkce  a  ) by neměl být použit pro data uložená (nebo načtená) mimo aktuální proces. Místo toho použijte serializaci založenou na JSON (pozor na úskalí). Toto jsou pravidla zavedená RFC T161647.

Důvod je dvojí: (1) data serializovaná tímto mechanismem nemohou být spolehlivě unserializována s novější verzí stejné třídy. A (2) vytvořená sériová data lze použít ke spuštění škodlivého kódu, což představuje vážné bezpečnostní riziko.

Někdy váš kód nebude řídit mechanismus serializace, ale bude používat nějakou knihovnu nebo ovladač, který je používán interně. V takových případech je třeba podniknout kroky ke zmírnění rizika. První výše uvedený problém lze zmírnit převedením jakýchkoli dat na pole nebo prosté anonymní objekty před serializací. Za druhé lze snad riziko zmírnit pomocí funkce whitelisting, kterou PHP 7 zavádí pro unserializaci.

Komentáře a dokumentace
Je nezbytné, aby váš kód byl dobře zdokumentován, aby ostatní vývojáři a opraváři chyb mohli snadno pochopit logiku vašeho kódu. Nové třídy, metody a proměnné členy by měly zahrnovat komentáře poskytující stručné popisy jejich funkčnosti (pokud to není zřejmé), i když soukromé. Kromě toho by všechny nové metody měly dokumentovat jejich parametry a návratové hodnoty.

Při dokumentaci využíváme značky a styl, podobný jako když se používá Doxygen (ostatně PHPDoc z něj vychází, takže se jejich styl navzájem moc neliší). Díky tomu lze dokumentaci automaticky generovat rovnou z komentářů v kódu (viz Manual:mwdocgen.php). Začněte blok Doxygenových komentářů pomocí, namísto formátování ve formátu Qt. Strukturální příkazy doxygen začínají. (Jako únikový znak použijte spíše  než   - oba styly fungují v Doxygenu, ale pro zpětnou a budoucí kompatibilitu si MediaWiki zvolila   styl.) Organizují vygenerovanou dokumentaci (pomocí ) a identifikují autory (pomocí značek  ).

Popisují funkci nebo metodu, parametry, které potřebuje (pomocí ) a to, co funkce vrací (pomocí  ). Formát parametrů je:

@param type $paramName Description of parameter

Pokud parametr akceptuje různé typy, použijte k jejich oddělení znak svislé čáry, neboli svislítka '|' (pipe), podobně jako u následujícího příkladu:

V popisu pokračujte na dalším řádku, odsazeném o jednu mezeru navíc.

Pro každé veřejné rozhraní (metoda, třída, proměnná, cokoli), které přidáte nebo změníte, zadejte značku, aby lidé rozšiřující kód prostřednictvím tohoto rozhraní věděli, že porušují kompatibilitu se starší verzí kódu.

FIXME obvykle znamená, že je něco špatného nebo zničeného. TODO znamená, že je zapotřebí vylepšení. Neznamená to nutně, že to bude osoba, která přidává komentář. HACK znamená, že bylo provedeno rychlé, ale nevhodné, nepříjemné nebo jinak suboptimální řešení okamžitého problému a nakonec by mělo být provedeno důkladnější přepsání kódu.

Záhlaví zdrojových souborů
Chcete-li vyhovět většině licencí, měli byste mít v horní části každého zdrojového souboru něco podobného následujícímu (specifické pro aplikace GPLv2).

Značky pro Doxygen
V našich zdrojových kódech používáme při vkládání poznámek následující značky, s nimiž pracuje Doxygen. Aby byla zajištěna konzistence vašeho souboru, zachovejte prosím při jejich použití i vy stejné pořadí, v jakém jsou uvedeny zde:

Poznámky k souboru:
 * @file
 * @ingroup
 * @author

Třídy a jejich vlastnosti:


 * @todo
 * @var
 * @stable, @deprecated, @internal, @private
 * @see
 * @since
 * @ingroup
 * @param
 * @return
 * @throws

Poznámky k testům
U testů používáme, mimo jiné, i následující poznámky. V tomto případě se nejedná o dokumentaci, protože mají význam pouze pro PHPUnit a svůj význam mají pouze při testování.


 * @depends
 * @group
 * @covers
 * @dataProvider

Integrace kódu
V kódu MediaWiki najdete i kódy, které jsou na ní zcela nezávislé a tím pádem je lze snadno implementovat do jiných aplikací. Zatímco některé z nich nyní existují jako oddělené knihovny, jiné zůstávají ve zdrojovém stromu MediaWiki (např. soubory v ). Kromě toho by měl být kód integrován do zbytku prostředí MediaWiki a měl by umožňovat, aby se s ním na oplátku integrovaly další oblasti codebase.

Viditelnost
Svoje metody (funkce) si nastavte jako public/protected/private (podle toho jak uznáte za vhodné). Ale není důvod k tomu, aby byly veřejné (public) všechny!

Globální objekty
Nepřistupujte k superglobálním proměnným PHP jako, , atp. přímo. Získávejte jejich hodnotu raději přes volání metody. Většinou jsou k dispozici různé metody, které vám umožní získat požadovanou hodnotu ve formě typu, jaký zrovna potřebujete. Takže hodnotu pro aktuální můžete zjistit z nejbližšího objektu, takže není vůbec nutné kvůli tomu volat. Stejně tak nepřistupujte přímo k. Použijte, pokud chcete získat IP adresu aktuálního uživatele.

Statické metody a jejich vlastnosti
Ve svém PHP statické metody a vlastnosti klidně používejte, jenom mějte neustále na paměti, jaký je rozdíl mezi  a. bude vždy odkazovat na funkce a proměnné v rámci třídy, zatímco  bude odkazovat na konkrétní podtřídu, která ji zavolá. Pro víc podrobností si přečtěte v dokumentaci k PHP o dědičnosti a pozdějších statických vazbách.

Třídy
Zapouzdřete svůj kód do objektově orientované třídy, nebo ho přidejte jako novou funkci do třídy již existující. Nepřidávejte nové globální funkce či proměnné, pokud to není nezbytné. Snažte se mít neustále na paměti rozdíl mezi třídami, které patří k 'backendu', jakou jsou například entity které pracují s databází, jako,  ,  , aj. A třídami co obsluhují 'frontend', jako,  ,   a jiné. Pokud není váš kód zrovna objektově orientovaný, je lepší jej umístit alespoň do statické třídy, jako jsou např. třídy  nebo.

Jako ochrana před nedostatkem soukromých členů třídy a metod v PHP 4 bude starší kód označen komentáři, jako je, které označují záměr; respektujte to, jako by to vynutil tlumočník.

Označte nový kód správnými modifikátory viditelnosti, včetně, pokud je to vhodné, ale nepřidávejte viditelnost existujícímu kódu bez předchozí kontroly, testování a refaktoringu podle potřeby. Obecně je dobré vyhnout se změnám viditelnosti, pokud neprovádíte změny ve funkci, které by stejně narušily její stará použití.

Jak ošetřit chyby
In general, you should not suppress PHP errors. The proper method of handling errors is to actually handle the errors.

For example, if you are thinking of using an error suppression operator to suppress an invalid array index warning, you should instead perform an check on the array index before trying to access it. When possible, always catch or naturally prevent PHP errors.

Only if there is a situation where you are expecting an unavoidable PHP warning, you may use PHP's operator. This is for cases where:


 * 1) Je nemožné předvídat chybu, která se chystá; a
 * 2) Chystáte se na řešení chyby vhodným způsobem poté, co k ní dojde.

We use PHPCS to warn against use of the at-operator. If you really need to use it, you'll also need to instruct PHPCS to make an exemption, like so:

An example use case is opening a file with. You can try to predict the error by calling  and , but unlike  , such file operations add significant overhead and make for unstable code. For example, the file may be deleted or changed between the check and the actual  call (see TOC/TOU).

In this case, write the code to just try the main operation you need to do. Then handle the case of the file failing to open, by using the  operator to prevent PHP from being noisy, and then check the result afterwards. For  and , that means checking for a boolean false return, and then performing a fallback, or throw an exception.

Exceptions that indicate programming errors should be one of the exceptions that ship with PHP or a more specific subclass, while exceptions that indicate errors that are relevant to the end user should be an ErrorPageError or one of its subclasses.

AtEase
For PHP 5 and earlier, MediaWiki developers discouraged use of the  operator due to it causing unlogged and unexplained fatal errors (r39789). Instead, we used custom  and   methods from the  library. The reason is that the at-operator caused PHP to not provide error messages or stack traces upon fatal errors. While the at-operator is mainly intended for non-fatal errors (not exceptions or fatals), if a fatal were to happen it would make for a very poor developer experience.

In PHP 7, the exception handler was fixed (example) to always provide such errors, including a stack trace, regardless of error suppression. In 2020, use of AtEase started a phase out, reinstating the at-operator. (T253461)