Manual:Coding conventions/PHP/cs

Tato stránka popisuje konvenci která se používá při psaní u PHP skriptů u. See also the that apply to all program languages, including PHP. If you would like a short checklist to help you review your commits, try using the.

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í. It is recommended to run this over files committed to Git.

Jsou také k dispozici pravidla pro PHP_CodeSniffer. For more information, see. The git repository  contains the PHP_CodeSniffer settings for MediaWiki code.

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

Odsazení s tabulátory, nikoli mezerami. Omezte řádky na 120 znaků (vzhledem k šířce karty 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:

Také obsah závorek oddělujte mezerami. Výjimkou je pouze situace, kdy závorky nemají žádný obsah. Naopak mezi jméno funkce a otevírací závorku pro její obsah mezeru nedávejte.

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é mezery nepoužívejte nikdy. 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. Remember, disk space is cheap, code readability is everything, "if" is English and " " is not. If you are using a multi-line ternary expression, the question mark and colon should go at the beginning of the second and third lines and not the end of the first and second (in contrast to MediaWiki's JavaScript convention).

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

Od PHP 7.0 je k dispozici null coalescing operator a v některých případech může nahradit ternárního operátora. Například místo místo toho můžete napsat následující:

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 [$escapes escape sequences] nebo [$variables variables]. For example, the regular expression requires an extra backslash, making it slightly more confusing and error-prone than. Also for people using US/UK qwerty keyboards, they are easier to type, since it avoids the need to press shift.

Nebojte se však používat dvojitě citovanou funkci interpolace řetězců PHP:

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

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

Někteří autoři rádi používají END jako koncový token, který je také názvem funkce PHP. To vede k IRC konverzacím, jako jsou následující:

Funkce a jejich parametry
Vyhněte se předávání obrovské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 jste v pokušení kódovat funkci jako je tato, zvažte raději předání asociativní sady pojmenovaných parametrů. If you are tempted to code a function like this, consider passing an associative array of named parameters instead.

Obecně se nedoporučuje ve funkcích používání booleovských parametrů. In, without looking up the documentation for , it is impossible to know what those parameters are meant to indicate. Much better is to either use class constants, and make a generic flag parameter:



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ě celý bod 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ý psací stroj. 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 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.

PHP má tři speciální literály, pro které je velká / malá / 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é syntaxi byste se však měli vyhnout širokým obloukem, protože řada textových editorů by se zobrazením takového kódu mohla mít problém. Takže použijte raději složené závorky:

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

Deklarování typů v parametrech funkce
Používejte vstupní deklaraci typu (podívejte se na naznačení typu – type hinting) a deklarujte i typ návratové hodnoty, všude kde to jen lze.

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 lower-CamelCase notaci. Jak demonstruje ukázkový příklad:

Pro názvy tříd používejte naopak Upper-CamelCase:. Použijte velká písmena s podtržítky pro globální a třídní konstanty:,. Jiné proměnné jsou obvykle malá nebo nižšíCamelCase; nepoužívejte podtržítka v názvech proměnných.

Používejte také zavedené prefixy. I ty v kódu napovídají oč 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ř. $wgtitle. Toto vždy používejte pro nové globály, abyste mohli snadno najít chybějící prohlášení „". 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 Wikimedia 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 (hlavní připojení)
 * – objekt  pro čtení, které není citlivé na souběžnost (může to být replika pouze pro čtení, mírně za hlavní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 mohou být viděny následující, ale v novém kódu jsou odrazovány:


 * – 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, nula, prázdné pole, atd.), Použijte.

Nepoužívejte k testování. Using in this situation could introduce errors by hiding misspelled variable names. Instead, use.

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 conversion to boolean. 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 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“ (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 projíždíte maticí, pokud nebudete muset, neprocházejte referencí. I přesto si uvědomte důsledky. (Viz http://www.king-foo.be/2010/10/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átoři rovnosti
Buďte opatrní s double-equals comparison operators. Triple-rovná se je obecně intuitivnější a měla by být upřednostňována, pokud nemáte důvod k použití dvojitých equals.


 * 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 jsou stejné posloupnosti znaků, použijte, například  je nepravda.

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 64bit IEEE floating point numbers. 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, představujte 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 je politika 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á 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é členů 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  ).

Používají se při popisu parametrů, které se předávají funkci (metodě), a i toho co funkce vrací. Při popisu parametrů to vypadá takto:

@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 zdrojácích 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
 * @deprecated
 * @class
 * @see
 * @since
 * @param
 * @return
 * @throws
 * @private

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
 * @expectedException
 * @expectedExceptionMessage

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. Equally, do not access directly; use  if you want to get the IP address of the current user.

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 podrobnosti si přečtěte v dokumentaci k PHP o dědičnosti a pozdní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é, co zastupují stránky a rozhraní co se vrací uživateli. Pokud není váš kód zrovna objektově orientovaný, je lepší ho umístit alespoň do statické třídy, jako jsou např. třídy  nebo. Try to be mindful of the distinction between 'backend' classes, which represent entities in the database (e.g.,  ,  , etc), and 'frontend' classes, which represent pages or interfaces visible to the user ( ,  ,  , etc.  Even if your code is not obviously object-oriented, you can put it in a static class (e.g.   or  ).

Vzhledem k tomu, že PHP 4 má nedostatek členů a metod soukromé třídy, bude starší kód označen komentáři, jako je, což naznačuje záměr; respektujte to, jako by to bylo vynuceno tlumočníkem.

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. It's generally a good idea to avoid visibility changes unless you're making changes to the function which would break old uses of it anyway.

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-operastor 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)