Coding Standard

Coding Standard

Každý tým by měl mít kvalitní infrastrukturu, která poskytuje a vyžaduje konzistentní výstup všech jeho členů. Coding standard je jedna z mnoha věcí, která drží projekt pohromadě. Z kusu kódu by nemělo být zřejmé, kdo ho napsal. Tým by měl mít společné konvence jak psát a formátovat kód. V přednášce budu mluvit o nástroji PHP_CodeSniffer, psaní vlastních pravidel (sniffů) a již hotových sniffech, které můžete použít. Možná se i dozvíte pár věcí o tom, jak funguje parsování zdrojového kódu v PHP.

95a298d2bffa1b46fd023a286a8a7e86?s=128

Ondřej Mirtes

June 03, 2016
Tweet

Transcript

  1. Coding Standard Ondřej Mirtes PHP Prague, 3. června 2016

  2. Code review Bez code review si neumím představit vývoj. Každý

    kód, co jde do masteru, by měli vidět alespoň dva lidé. Klesne vám míra WTF a kódu bude rozumět víc lidí.
  3. Code review • Kód dělá to, co má • Nezabije

    servery • Splňuje SOLID • Smysluplně rozšiřuje aktuální kód • ... • Je čitelný • Naformátovaný podle dohodnutých pravidel Poslední dva body jdou automatizovat, šetří to práci při code review. Pravidla jdou formalizovat. Všechen kód by měl vypadat stejně a nemělo by být poznat, kdo ho psal, pracují s ním všichni.
  4. Coding standardem proti bugům if ($isFoo && $isBar)
 doSomething(); Kromě

    sjednocení podoby kódu lze pomocí coding standardu i zamezit některým bugům. Okolo ifu byste vždy měli mít složené závorky {}, i když obsahuje (právě teď) pouze jeden příkaz.
  5. Coding standardem proti bugům if ($isFoo && $isBar) {
 doSomething();


    }
  6. Coding standardem proti bugům if ($foo == 0) {
 


    } Nepřesná porovnání jsou zdrojem mnoha problémů. Zde např. bude vyhodnocena podmínka na true, pokud $foo bude jakýkoli string nezačínající číslicí.
  7. Coding standardem proti bugům if ($foo === 0) {
 


    } Kdykoli někde vidím == nebo !=, tak to interpretuji jako "vůbec nevím, co v té proměnné vlastně je".
  8. Přehlednější diffy $arr = [
 1,
 2
 ]; Coding standard

    kromě snížení chybovosti a zpřehlednění kódu má pozitivní dopad i na verzování. Čárka za posledním prvkem víceřádkového pole vede k přehlednějším diffům.
  9. Přehlednější diffy $arr = [
 1,
 - 2 
 +

    2,
 + 3 
 ]; Přidal jsem jeden prvek do pole, ale diff této změny je nepřehledný.
  10. Přehlednější diffy $arr = [
 1,
 2,
 ];

  11. Přehlednější diffy $arr = [
 1,
 2,
 + 3,
 ];

    S čárkou za posledním prvkem už dává smysl.
  12. Continuous Integration • Aplikaci lze vůbec spustit – nainstalovat závislosti,

    zkompilovat DI kontejner… • Syntax errory: php -l • Coding standard • Testy • Další kontroly - např. doctrine orm:validate-schema • Kompilace a kontrola CSS, JavaScriptu, …
  13. Continuous Integration

  14. PHP_CodeSniffer squizlabs/php_codesniffer

  15. ruleset.xml <?xml version="1.0"?>
 <ruleset name="MyStandard">
 <rule ref="AnotherStandard/ruleset.xml" />
 <rule ref="Slevomat.Namespaces.ReferenceUsedOnly">


    ...
 </rule>
 </ruleset> CodeSniffer se bohužel konfiguruje pomocí XML. Do <rule> lze uvést buďto cestu k dalším rulesetům (a "includovat" tak další standardy) nebo konfigurovat konkrétní sniffy.
  16. ruleset.xml 
 
 
 <rule ref="AnotherStandard/ruleset.xml">
 <exclude name="Squiz.PHP.InnerFunctions.NotAllowed"/>
 </rule> Při

    includnutí dalšího rulesetu lze vynechat některá pravidla, která obsahuje, v případě, že vám nevyhovují.
  17. ruleset.xml <rule ref="Slevomat.Namespaces.ReferenceUsedOnly">
 <properties>
 <property
 name="allowFullyQualifiedExceptions"
 value="true"
 />
 <property name="allowPartialUses"

    value="false"/>
 </properties> 
 </rule> Konkrétní sniffy lze konfigurovat, pokud to umožňují. Tato nastavení se propisují do public properties před spuštěním daného sniffu.
  18. Kde shánět sniffy? • github.com/squizlabs/PHP_CodeSniffer
 nebo: • edorian.github.io/php-coding-standard-
 generator/#phpcs Sniffy

    se shání velmi těžko. Samotný repozitář CodeSnifferu jich hromadu obsahuje, musíte se ale orientovat podle jejich názvu nebo implementace, nejsou nikde sepsané. Někdy je snazší si ho napsat sám
  19. Z čeho se sniff skládá • Public properties – konfigurace

    • register() • process(
 \PHP_CodeSniffer_File $phpcsFile,
 $tokenPointer
 )
  20. Tokenizace zdrojáku public function doFoo(): Foo
 {
 return $this->doBar();
 }


    
 T_PUBLIC, T_WHITESPACE, T_FUNCTION, T_WHITESPACE, T_STRING, T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS, T_COLON, T_WHITESPACE, T_RETURN_TYPE, T_WHITESPACE, T_OPEN_CURLY_BRACKET, T_WHITESPACE, T_RETURN, T_WHITESPACE, T_VARIABLE, T_OBJECT_OPERATOR, T_STRING, T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS, T_SEMICOLON, T_WHITESPACE, T_CLOSE_CURLY_BRACKET
  21. Jaké tokeny mě zajímají? public function register()
 {
 return [


    T_IF,
 T_ELSEIF,
 T_DO,
 ];
 }
  22. Pro každý token, na který PHPCS narazí,
 se zavolá: public

    function process(
 \PHP_CodeSniffer_File $phpcsFile,
 $tokenPointer
 ) {
 $tokens = $phpcsFile->getTokens();
 $token = $tokens[$tokenPointer];
 }
  23. Pole s tokenem obsahuje: "content" => "doBar",
 "code" => 319,

    // T_STRING
 "type" => "T_STRING",
 "line" => 8,
 "column" => 17,
 "conditions" => [
 2 => 361, // T_CLASS
 12 => 346, // T_FUNCTION
 ],
  24. Metody k dispozici $tokenPointer = $phpcsFile->findNext(
 $types,
 $start,
 $end =

    null,
 $exclude = false,
 $value = null,
 $local = false
 );
  25. Metody k dispozici $tokenPointer = $phpcsFile->findPrevious(
 $types,
 $start,
 $end =

    null,
 $exclude = false,
 $value = null,
 $local = false
 );
  26. Označení chybného zdrojáku $phpcsFile->addError(
 $error,
 $tokenPointer,
 $code = '',
 ...


    ); Pokud sniff reportuje více různých druhů chyb, $code slouží k jejich rozlišení. Můžete pak excludovat konkrétní code a nikoli celý sniff.
  27. Jak naimplementovat kontrolu? $arr = [
 1,
 2
 ]; Zaregistruju

    se na otevírací závorku pole a hledám konečnou. Musím ale počítat se zanořeným polem, takže mě zajímá závorka na stejné úrovni (ve stejné hloubce). Jakmile na ní narazím, hledám první newhitespacový token, měla by to být čárka. Pokud není, nahlásím chybu.
  28. Jak naimplementovat kontrolu? if ($isFoo && $isBar)
 doSomething(); Zaregistruju se

    na T_IF, najdu jeho otevírací závorku a pak hledám konečnou. Opět počítám se zanořenými podmínkami. Po konečné závorce by měl být první newhitespacový token {. Pokud není, nahlásím chybu.
  29. Jak spustit PHPCS? vendor/bin/phpcs
 --standard=ruleset.xml
 --extensions=php
 --tab-width=4
 -s // show

    sniff codes
 -p // show progress
 app
 tests
  30. Samoopravné sniffy ---------------------------------------------------------------------- FOUND 1 ERROR AFFECTING 1 LINE ----------------------------------------------------------------------


    38 | ERROR | [x] Multiline arrays must have a trailing comma after the
 | | last element
 | | (SlevomatCodingStandard.Arrays.TrailingArrayComma)
 ----------------------------------------------------------------------
 PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
 ---------------------------------------------------------------------- Pokud je u chybové hlášky [x], znamená to, že umí prohřešek CodeSniffer i opravit.
  31. Samoopravné sniffy vendor/bin/phpcbf
 --standard=ruleset.xml
 --extensions=php
 --tab-width=4
 -s // show sniff

    codes
 -p // show progress
 app
 tests
  32. Slevomat Coding Standard • Nepoužité privátní properties a metody •

    Seřazené uses • Nepoužité uses • Zakázané yoda podmínky • Sniffy ohledně namespaces • Chystané PHP 7-specific sniffy (2.0) github.com/slevomat/coding-standard
  33. @OndrejMirtes