Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

Proč Nette nedodržuje standardy PHP-FIG / PSR?

„Proč Nette musí jít za každou cenu proti proudu a odmítá respektovat standardy PHP-FIG?“

Tohle je sugestivní otázka, často kladená v souvislosti s tím, proč Nette odsazuje tabulátory, a nikoliv mezerami. Pojďme to rozebrat postupně.

V první řadě, PHP Framework Interoperability Group (PHP-FIG) netvoří obecné standardy, jde o soubor pravidel, která si tvoří určitá viditelná skupina vývojářů sama pro sebe. Ve FAQ se uvádí, že původní název „PHP Standards Group“ byl změněn právě proto, že byl zavádějící. Doslova říkají „pokud chcete dodržovat naše standardy, prosím, ale není to našim záměrem.

Jelikož naprostá většina pravidel coding standardů PHP-FIG se shoduje se standardem Nette, dá se říci, že Nette je, až na drobné výjimky, dodržuje také.

Dokument PSR-0 Autoloading Standard specifikuje, že každá třída musí být uložena v souboru, jehož cesta přesně odpovídá názvu třídy. Jelikož Nette disponuje pokročilejším autoloadingem (a výkonnějším, viz níže) než mají ostatní frameworky, nemusí se tohoto pravidla držet z technické nutnosti, nicméně jde o přehledný způsob organizace souborů, proto jej také používá. Jedinou odchylkou jsou definice výjimek, které je někdy praktičtější umístit do jednoho souboru – jsou tak pěkně pohromadě a např. adresář Utils zůstává výrazně přehlednější.

PSR-0 odchylky netoleruje, právě kvůli technickým omezením, které se Nette netýkají (a v dnešní době Composeru se netýkají vlastně žádné knihovny). Volání po rigidním dodržení PSR-0 by bylo zbytečným krůčkem zpět.

Dokument PSR-1 Basic Coding Standard definuje základní pravidla pro obsah PHP souboru, která se plně slučují s coding standardem Nette.

Dokument PSR-2 Coding Style Guide je obsáhlou definicí přesných pravidla pro zápis kódu. Takřka kompletně se slučuje se standardem Nette, krom tří dvou bodů:

  • Nette odděluje use deklarace čárkou
  • zatímco PSR vyžaduje psát true, false, null malými písmeny, Nette (mimochodem v souladu s dokumentací PHP) používá velká písmena
  • Nette odsazuje pomocí tabulátorů, PSR-2 vyžaduje mezery.

Dokument PSR-3 Logger Interface definuje rozhraní Psr\Log\LoggerInterface, čímž opouští roli kodifikátora pravidel psaní kódu. Dle mého je rozhraní definováno špatně a řeší problém, který neexistuje. Ale tohle téma nechci probírat, ani v komentářích. Můžete si přečíst třeba názor ircmaxella + pokračování. Chystaný PSR-11 Container Interface je pak příkladem naprostého nepochopení Dependency Injection.

Dokument PSR-4 Autoloader určuje, jak má být implementovaný autoloader pro PSR-0. Jak jsem zmiňoval, tohle téma je pro Nette a Composer passé. Navíc se v praxi ukázalo, že jde o řešení s negativním dopadem na výkon, pročež Composer nabízí volbu --optimize, která převede PSR-0 na classmap, kterou právě používá Nette RobotLoader.

Když už je shoda mezi PSR a standardem Nette tak velká, proč nezměnit těch pár drobností a nebýt 100% vyhovující? Je v tom tvrdohlavost? Nebo zmíněná snaha jít proti proudu?

Ani jedno. Ohledně znaku pro odsazování jsem se po celoživotním používání mezer nechal netvrdohlavě přesvědčit a přešel na tabulátory. Stalo se tak rok před vznikem PHP-FIG, tedy onoho proudu, proti kterému bych měl jít.

Zajímavé je, že dokonce i řada samotných členů PHP-FIG používají tabulátory. Jeden ze zakladatelů Paul M. Jones mi k tomu napsal: „Yes, the vote was roughly 2:1 in favor of spaces. The tab folk are as a result not PSR-2 compliant.“

Jednoduše prostě neznám důvod, proč takhle zasáhnout do kódu a leccos tím zkomplikovat. Nemáme jen jeden jediný standard, tabulátory používá třetina všech projektů. Navíc otázka tabulátoru vs mezery je naprosto malicherná a nemá naprosto žádný vliv na interoperabilitu knihoven.

Jediné podstatné je být konzistentní a v celém kódu dodržovat stejná pravidla. Nesmí být poznat, že kód psalo více lidí. Což Nette striktně odjakživa respektuje.

Komentáře

  1. Honza T #1

    PSR-4 neřeší, jak implementovat PSR-0 autoloader, ale nahrazuje PSR-0, primárně kvůli tomu, že PSR-0 je dost na nic, když používáš Composer, neboť vznikají šíleně hluboké cesty, jako např. /vendor/nette/database/src/Nette/Database. PSR-4 to umožňuje zkrátit na /vendor/nette/database/src.

    před 2 lety | odpovědět | reagoval [2] David Grudl
  2. David Grudl http://davidgrudl.com #2

    avatar

    #1 Honzo Te, díky za doplnění.

    Když používáš Composer, tak je IMHO na nic i PSR-4.

    před 2 lety | odpovědět
  3. Tomáš Fejfar http://blog.tomasfejfar.cz #3

    avatar

    Nette preferuje oddělovat use deklarace čárkou

    Takže když přidáš na konec / odebereš poslední use, tak musíš udělat diff o řádek výš. Stejně jako se píše za poslední položku pole čárka (abys neměl diff když přidáš další).

    zatímco PSR vyžaduje psát true, false, null malými písmeny, Nette v souladu s dokumentací PHP používá velká písmena

    $myBool = TRUE; var_dump($myBool); // bool(true) – proč to dělat jednoduše, když to jde složitě a máš dvě různé vizuální reprezentace. To, že to má stejně podivně dokumentace je zajímavé, ale není to důvod to dělat stejně špatně :)

    Nette odsazuje pomocí tabulátorů, PSR-2 vyžaduje mezery

    je mi celkem jedno, krom chvíle kdy třeba někde sahám do PHP z vimu nastaveného na 8zn tab. Takže i když chápu, že někdo má radši třeba 2zn. nebo 6zn., tak já mám radši všude stejně. (ano, znám vimrc, ale prostě ho všude nemám nebo jsem pod rootem, kde to používá víc lidí nebo tak něco)

  4. hacafrakus #4

    avatar

    Tabulátory jsou podle mne jediná správná cesta, protože jsou pro každého nastavitelné na jiný počet mezer a osobně používám v editorech výhradně proporcionální font (výhodu pevné šířky jsem nějak nepostřehl, ačkoliv se používá snad všude).

    Osobně mne ale víc trápí třeba namespaces. Asi je pořád vnímám trochu moc jako adresářovou strukturu, ale zkrátka mi název App\FrontModule\Presenters\ArticlesPresenter připadá divný, pohrávám si s myšlenou, jestli se na to nevykašlat a nepoužívat raději App\Modules\Front\Presenters\Articles. Jenže když potom někdo používá hodně use (já osobně mám raději používání názvů včetně namespace, nebo alespoň části), tak nebude třeba hned vědět, co zmiňované Articles znamená.

    před 2 lety | odpovědět | reagoval [6] David Grudl
  5. David Grudl http://davidgrudl.com #5

    avatar

    #3 Tomáši Fejfare, proč se vztekáš? Tvrdím snad, že ty 3 rozdíly oproti PSR-2 jsou přednost Nette? Pak jsi nic nepochopil. Píšu, že pokud si někde ňácí kluci vyrobí nový standard, není to důvod se hned zbláznit a přepsat existující kód.

    Argument s var_dump je čirá ujetost, no klidně pošli do PHP pull request, ať už s opravou var_dump nebo dokumentace.

    před 2 lety | odpovědět | reagoval [8] Hrach [11] ivan
  6. David Grudl http://davidgrudl.com #6

    avatar

    #4 hacafrakusi, používám Module\Front\Presenters\ViewPresenter, tedy moduly bez postfixu Module, ale u tříd ponechávám kromě specifičnosti i obecnost, tedy postfix Presenter. Viz také https://phpfashion.com/…ostory-v-php

    před 2 lety | odpovědět | reagoval [7] hacafrakus [9] enumag
  7. hacafrakus #7

    avatar

    #6 Davide Grudle, To je rozumné řešení. Na ten odkazovaný článek jsem si právě taky vzpomněl, díky.

    před 2 lety | odpovědět
  8. Hrach http://www.skrasek.com #8

    avatar

    #5 Davide Grudle, neprijde mi, ze by se Tomáš jakkoliv vztekal. Proč na něj účtočíš, že nic nepochopil? Normálně okomentoval článek.

    Jinak musim zminit https://github.com/…tte/pull/952. Ale vic to komentovat nebudu, ještě bych se mohl vztekat ;)

    před 2 lety | odpovědět | reagoval [12] David Grudl [15] ondra
  9. enumag http://m33.cz/ #9

    avatar

    #6 Davide Grudle, Tvůj namespace Module\Front\Presenters\ViewPresenter mi připadá nekonzistentní – použil bych buď Modules a Presenters nebo Module a Presenter. Moje osobní preference je to druhé.

    před 2 lety | odpovědět
  10. Jakub Bouček http://jakub-boucek.cz #10

    avatar

    #3 Tomáši Fejfare, var_dump() nevypisuje PHP kód, ale má specifický zápis. Něco jiného by bylo porovnání s nějakou Print_r() nebo tak něco.

    před 2 lety | odpovědět
  11. ivan #11

    #5 Davide Grudle, „pokud si někde ňácí kluci vyrobí nový standard, není to důvod se hned zbláznit a přepsat existující kód“ výstižné, souhlasím.

    před 2 lety | odpovědět
  12. David Grudl http://davidgrudl.com #12

    avatar

    #8 Hrachu, slovo vztekal nebylo namístě, chtěl jsem napsat vzrušoval. Prostě termín pro emoci, která člověka přiměje ke zcela neutrálnímu konstatování, že se dva coding standardy liší, vykonstruovat argumentaci, že jeden je špatně. Co teprve až #3 Tomáš Fejfar zjistí, že var_export() (což je jediná relevantní funkce) píše NULL velkým a vkládá závorku mezi array a (. Půjde na PHP-FIG vysvětlit, jak to dělají špatně + smajlík?

    Mně je úplně šumák, jestli kód používá mezery, TRUE nebo true a jak se píšou use. Ale pokud mám coding style měnit, tak chci slyšet pořádný důvod. Protože mi jde o konzistenci.

    Změna zápisu use není jeden kommit do Nette, repozitářů je víc, příklady, dokumentace, tutoriály, jiné projekty, mnoho větví, mezi kterými často porovnávám atd. Chceš-li to udělat, prosím, ale důsledně.

    před 2 lety | odpovědět | reagoval [13] Honza Marek [25] Hrach
  13. Honza Marek #13

    avatar

    #12 Davide Grudle, Na to use bych možná udělal anketku, jak to lidi píšou. Nemám představu. Ale kdyby třeba 90 % používalo na každém řádku use, třídu a středník, mělo by to tak být i v Nette. Samozřejmě to nemá vysokou prioritu, protože je to interní záležitost kódu a na uživatele Nette to nemá vliv. Nicméně dobrý coding standard by neměl být příliš originální.

    před 2 lety | odpovědět | reagoval [14] ivan
  14. ivan #14

    #13 Honzo Marku, Nejsem sice uživatel Nette (tak co se do toho …, že), ale nemyslím si, že je nejpřínosnější řešit, jaké nové formátování kódu zrovna většinově frčí a na tom ubíjet drahocený vývojový čas. To se pak každých pár let budou po dlouhých diskuzích měnit taby za mezery a zase zpět.
    Čitelnost kódu je víc o pojmenování a vnitřní logice, než o formátování. Jistě už mnozí viděli úhledně napsanou prasárnu.
    A to se mi třeba z těch dvou variant use zdá být lepší ta use na začátku (je tu ovšem verze třetí, těm předešlým podobná :) ).

    před 2 lety | odpovědět
  15. ondra #15

    #8 Hrachu, :D to sou merge requesty, ze na to mate cas

    ondro, je-li to možné, piš prosím s diakritikou.

    sry

    před 2 lety | odpovědět
  16. ondra #16

    btw:

    http://blog.golang.org/…mt-your-code

    pokud chces zmenit coding style, znamena to merge request na tenhle nastroj,

    no neni to dokonale?

    před 2 lety | odpovědět
  17. Jakub Vrána http://php.vrana.cz/ #17

    avatar

    Argumenty proti čárce v use jsou očividné:

    1. Nepřehledné diffy, pokud se mění první nebo poslední položka.
    2. Nepřehledné formátování – každá položka začíná na jiném sloupci, pokud zrovna nepoužívám odsazení 4 a neproporcionální písmo. Ale i v tom případě první řádek vypadá podstatně jinak než ostatní.

    Argumenty pro čárku prakticky neexistují:

    1. Trochu méně psaní vyvažuje to, že novou deklaraci často přidám zkopírováním existujícího řádku a jeho úpravou. To je opět problematické u prvního a posledního řádku.
    2. Menší výsledná velikost je zanedbatelná, při minifikaci se to navíc samozřejmě může spojit.

    Argumenty jsou podle mě dost závažné na to, že stojí za to to změnit nehledě na PSR-2. Znehodnocení blame, což je největší problém rozsáhlých změn, tady moc nevadí, protože historie use není moc zajímavá.

    před 2 lety | odpovědět
  18. Jakub Vrána http://php.vrana.cz/ #18

    avatar

    Sám jsem true, false a null v PHP vždycky psal malými písmeny, ale je fakt, že to jsou konstanty, nikoliv klíčová slova, takže by se měly psát velkými. Jsou tak ostatně i definované: zend_constants.c:138.

    před 2 lety | odpovědět | reagoval [19] Martin Koutný
  19. Martin Koutný #19

    avatar

    #18 Jakube Vráno, Jakube, proč následující kód vypíše Ano, přestože podle get_defined_constants je konstanta TRUE == bool(false)?

    <?php
    define('TRUE', false);
    
    if(TRUE) echo 'Ano';
    else echo 'Ne';
    
    var_dump(get_defined_constants());
    před 2 lety | odpovědět | reagoval [22] Jakub Vrána
  20. David Grudl http://davidgrudl.com #20

    avatar

    Konstanty jsou konstanty, nemůžeš je měnit.

    před 2 lety | odpovědět
  21. Ondřej Brablc http://brablc.com/ #21

    avatar

    Proti tabům hovoří vzrůstající obliba webových nástrojů pro správu sdíleného repozitáře kódu. Bohužel u nich není tak snadné nastavit pro každého uživatele a potenciálně pro každý typ souboru šířku tabu. Hlavní argument tabů – tedy, že to každý vidí tak jak chce, na webu vypadá tak, že to každý vidí, tak jak určitě nikdo nechtěl (8 mezer na tab: https://github.com/…369f47c3896a ).

    Navíc správné nastavení editoru vyžaduje určité úsilí a čím méně kódu píšu, tím méně mě baví hledat kde a jak co nastavit. Abych předešel chybám (protože mezerník občas stisknu), tak si musím zobrazovat white characters. To mi kód čitelnější nedělá.

    Pracoval jsem asi tak 15 let v týmech bez tabů – nikdy žádná třenice, žádný problém. Nastoupil jsem do firmy, kde taby byly jediný možný výklad světa, a do dneška mě to zdržuje v práci.

    Když odhlédneme od toho, že každý z tab uživatelů považuje za nutné používat jiné odsazení než zbytek týmu, zdržovaly by vás mezery nějak v práci?

    před 2 lety | odpovědět | reagoval [23] David Grudl
  22. Jakub Vrána http://php.vrana.cz/ #22

    avatar

    #19 Martine Koutný, get_defined_constants(true) objasní, co se děje. Jde o bug PHP, HHVM to má opravené. Viz http://3v4l.org/VC0q9.

    před 2 lety | odpovědět
  23. David Grudl http://davidgrudl.com #23

    avatar

    #21 Ondřeji Brablci, prohlížeče (krom IE, jak jinak) podporují tab-size, podporuje to dokonce i GitHub přidáním ?ts=4. Otázka je, proč jako výchozí hodnotu má 8.

    Stejně tak nechápu, proč jsou v dnešní době editory tak hloupé a nepoznají, zda soubor používá tabulátory nebo mezery. Vychozí nastavení by měla být detekce.

    Taky jsem používal mnohem delší část programátorského života mezery a mám pocit, že přechodem na taby se nic nezměnilo, tj. dnes řeším nechtěné mezery, předtím jsem řešil nechtěné taby. Nakonec jsem si na to udělal skript.

    Používání tabů nebo mezer není o tom, že by to zdržovalo nebo nějak vylepšovalo práci. Vidím to jako technický detail, který má řešit editor. Mně je úplně jedno, co z toho používám, jen se to prostě nedá měnit. Teoreticky při rozdělení Nette bylo možné takovou změnu podstoupit, ale nikdo po ní nevolal.

    A někdy odsazuji obojím, když potřebuji provést jemné zarovnání mezerami. Typickým příkladem v PHP je doc:

    /**
     * ....
     */

    Nebo v NEONu:

    - one: 1
      two: 2
      three: 3
    před 2 lety | odpovědět
  24. bene #24

    Ohledně psaní use jsem chtěl napsat to co Jakub, ale není třeba opakovat, co Jakub popsal perfektně.
    Jen bych doplnil, že stejný „problém“ je i s konstantami, které jsou v Nette zapsány stejně jako use.
    Kdysi jsem psal konstanty způsobem jako jsou zapsány v Nette a už bych podruhé stejnou chybu neudělal.

    Velikost písmen u true, false a null nehraje roli. Důležité je, aby to bylo v rámci projektu/knihovny jednotné. Sám používám malá písmena, protože to je rychlejší na psaní (není třeba držet Shift).

    Pracuji zouběžně na projektech, které používají jak tabulátory tak mezery a od tohoto problému mě odstiňuje IDE. Nezaznamenal jsem žádný problém s mou výkoností. Navíc nejlépe je po dokončení třídy kód přeformátovat pomocí IDE stisknutím třech tlačítek, takže ve finále ani „nejde“ udělat chybu ve formátování.

    Co mi ale vadí je kombinace tabulátorů a mezer např. při zarovnávání jak píšeš. Vytrácí se pak jednotnost, o kterou ti tolik jde.

    před 2 lety | odpovědět
  25. Hrach http://www.skrasek.com #25

    avatar

    #12 Davide Grudle, Davide, ono v zime roku 2013 nebylo tolik repozitaru, ci dokumentaci v gitu. Takze bych si troufnul tvrdit, ze zmena byla vcelku komplexni a neodbyta. Dnes to bude vyrazne slozitejsi. Kazdopadne, i takovato zpetna vazba se ceni – diky – a hodila by se u PR.

    před 2 lety | odpovědět
  26. v6ak https://www.v6ak.com #26

    Jsem zvyklý na tabulátory a mám je radši, ale bez větších problémů jsem si zvykl na to, ze v jednom projektu používáme mezery.

    Podporu editorů řeší http://editorconfig.org/ . Já používám IntelliJ IDEA, kolega Vim, jiný snad Sublime, ale nikdo jsme si nemuseli nastavovat editor ručně. Pokud se editorconfig rozšíří, bude to fajn.

    před 2 lety | odpovědět
  27. Šaman http://miroslav-mrazek.cz/ #27

    avatar

    Co se týče mezer místo tabů, vadí mi na nich, že:

    • Pokud nepoužívám IDE, ale nějaký nízkoúrovňový editor, musím pro dosažení stejného efektu stisknout klávesu 4×. Což teprve při větším zanořování. Nestává se to často, ale občas ano.
    • I pokud používám chytré IDE, tak pokud mi jeden tab nahradí čtyřmi mezerami, co se má stát pokud stisknu backspace? Ani já nevím, jestli by se měly ubrat 4 mezery, nebo jen jedna. IDE sice něco vymyslí, ale často špatně… Další věc je pohyb mezi odsazeními – při použití mezer musím šipku stisknout 4×, nebo se zase spolehnout na to, že IDE správně odhadne, jestli se chci v těch mezerách posouvat o jednu, nebo o celý tab.
    • 4 mezery jsou co? Prostě 4 mezery. A protože jedna je pro optické odsazení kódu málo, dáme ji 4×. Takže asi stejné jako řešit větší mezeru mezi odstavecma několikanásobným tagem BR. Tab je semanticky správné odsazení textu o jednu úroveň. Mezera nikoliv.
    • Mezery pro odsazování používám jen pro optické zarovnání třeba PhpDocu, nebo vyrovnání anotací @param type $name do sloupců. To však nemá žádný semantický význam a je to čistě jen kosmetika. Navíc diskutabilní, poslední dobou se tomu vyhýbám (kromě té jedné mezery pro srovnání hvězdiček v PhpDoc bloku).
    před 2 lety | odpovědět

Zanechat komentář

Text komentáře
Kontakt

(kvůli gravataru)



*kurzíva* **tučné** "odkaz":http://example.com /--php phpkod(); \--