PHP_CodeSniffer
Andy Grunwald

22. September 2010, PHP Usergroup Düsseldorf / Duisburg / Krefeld
Über mich

✤   Andy Grunwald

✤   Fachinformatiker:
    Anwendungsentwicklung

✤   wmdb Systems GmbH

✤   PHP seit 2004

✤   Open Source Fan

✤   Chaot
Agenda

✤   Was ist der PHP_CodeSniffer?

✤   Wozu ist er gut?

✤   Wo kann man Ihn einsetzen?

✤   Gibt es eigene Bezeichnungen?

✤   Gibt es fertige Standards?

✤   Was kann er?

✤   Wie funktioniert er?
Agenda

✤   Was sind Tokens?

✤   Wie sieht ein Standard aus?

✤   Wie sieht ein Sniff aus?

✤   Gibt es auch Unit Tests?

✤   Hast du Tipps für uns?

✤   Wo gibt es weitere
    Informationen?
Was ist der PHP_CodeSniffer?

✤   Tool zur statischen Code Analyse

✤   „Analysiert Dateien und erkennt Verletzungen von definierten
    Regeln“

✤   PHP (, JS, CSS) Qualitätssicherungs-Tool

✤   Greg Sherwood (Product Development Manager, Squiz Labs)

✤   Vorraussetzung: PHP >= 5.1.2 + exttokenizer
Was ist der PHP_CodeSniffer?

✤   BSD License

✤   PEAR-Package

    ✤   „Package Maintenance Rank: 4 of 202 packages“.

✤   Aktuelle Version: 1.3.0 RC1 (Stable: 1.2.2)

✤   Sehr aktives Projekt

✤   Schnelle Reaktionszeiten auf Tickets (Features / Bugs)
Wozu ist er gut?


✤   SourceCode bleibt sauber und
    konsistent

✤   Coding Standards

✤   Bug Patterns

✤   Perfomance Patterns
Wo kann man Ihn einsetzen?

✤   Manuelle Analyse auf der Shell

✤   Continuous Integration-Server
    (Hudson,
    PHPUnderControl, ...)

✤   SVN-Hook(s)

✤   IDE (Eclipse via PTI, Netbeans
    via Plugin von Benjamin
    Eberlei)
Gibt es eigene
Bezeichnungen?

✤   „Sniff“

    ✤   Eine Regel die einen
        bestimmten Zustand prüft

✤   „Standard“

    ✤   Eine Zusammenstellung von
        verschiedenen Sniffs
Gibt es fertige Standards?

✤   Auflistung installierter Coding
    Standards: „phpcs -i“

✤   MySource
                                     PHP_CodeSniffer
✤   PEAR

✤   PHPCS

✤   Squiz

✤   Zend
Was kann er?

✤   Mit einem Standard „sniffen“

✤   Mit bestimmten Sniffs „sniffen“

✤   Ordner [Rekursiv] /Einzelne
    Datei „sniffen“

✤   Ordner / Dateien via Pattern
    ignorieren

✤   Ausgabe in verschiedenen
    Formaten (XML, CSV,
    Checkstyle, ...)
Wie funktioniert er?


✤   Angegebener Standard wird analysiert („register()“)

✤   Datei wird eingelesen und durch exttokenizer verarbeitet

✤   Tokens werden durchlaufen

✤   Sniff („process()“) wird bei registriertem Token aufgerufen

✤   Fehler werden gesammelt und ausgegeben
Was sind Tokens?



✤   Teilung von
    Sprachkonstrukten /
    SourceCode in einzelne Zeichen
Was sind Tokens?

                                     T_CONTINUE
                                                    T_DO
                                       T_ISSET
                                                   T_NEW
                                     T_SWITCH
✤   Teilung von                                 T_FOREACH
                                     T_CLASS
    Sprachkonstrukten /
    SourceCode in einzelne Zeichen      T_BOOLEAN_AND
                                     T_PUBLIC
                                                   T_PRIVAT
                                       T_CATCH
                                     T_WHILE     T_EVAL
Was sind Tokens?

                   <?php
                   function foo($bar){
                   	 return ($bar + 1);
                   }
                   ?>
Was sind Tokens?

                   <?php
                   function foo($bar){
                   	 return ($bar + 1);
                   }
                   ?>
Was sind Tokens?

                   <?php
                   function foo($bar){
                   	 return ($bar + 1);
                   }
                   ?>
✤   T_OPEN_TAG
Was sind Tokens?

                   <?php
                   function foo($bar){
                   	 return ($bar + 1);
                   }
                   ?>
Was sind Tokens?

                           <?php
                           function foo($bar){
✤   T_FUNCTION             	 return ($bar + 1);
    T_WHITESPACE           }
    T_STRING
    T_OPEN_PARENTHESIS     ?>
    T_VARIABLE
    T_CLOSE_PARENTHESIS
    T_OPEN_CURLY_BRACKET
    T_WHITESPACE
Was sind Tokens?

                   <?php
                   function foo($bar){
                   	 return ($bar + 1);
                   }
                   ?>
Was sind Tokens?

                          <?php
✤   T_WHITESPACE
    T_RETURN              function foo($bar){
    T_WHITESPACE          	 return ($bar + 1);
    T_OPEN_PARENTHESIS    }
    T_VARIABLE
    T_WHITESPACE          ?>
    T_PLUS
    T_WHITESPACE
    T_LNUMBER
    T_CLOSE_PARENTHESIS
    T_SEMICOLON
    T_WHITESPACE
Was sind Tokens?

                   <?php
                   function foo($bar){
                   	 return ($bar + 1);
                   }
                   ?>
Was sind Tokens?

                            <?php
                            function foo($bar){
                            	 return ($bar + 1);
                            }
✤   T_CLOSE_CURLY_BRACKET   ?>
    T_WHITESPACE
Was sind Tokens?

                   <?php
                   function foo($bar){
                   	 return ($bar + 1);
                   }
                   ?>
Was sind Tokens?

                   <?php
                   function foo($bar){
                   	 return ($bar + 1);
                   }
                   ?>
✤   T_CLOSE_TAG
Was sind Tokens?

                               [type] => T_STRING
✤   Code: Wert der Konstante   [code] => 307
                               [content] => foo
✤   Type: Konstantenname       [line] => 2
                               [column] => 10
✤   Content: Realer Content
                               [code] => 370
✤   Line: Zeilennummer         [content] => ?>
                               [type] => T_CLOSE_TAG
✤   Column: Zeichenanzahl      [line] => 5
                               [column] => 1
Wie sieht ein
Standard aus?

✤   Standard-Konfiguration

    ✤   ruleset.xml

    ✤   FooCodingStandard.php

✤   Dokumentation

✤   Sniffs nach Kategorien

✤   Unit Tests nach Kategorien
Wie sieht ein Standard aus?
                               <?xml version="1.0"?>
                               <ruleset name="PEAR">
                                <description>The PEAR coding standard.</description>

                                <!-- Include some additional sniffs from the Generic /
                               PEAR standard -->
                                <rule ref="Generic.PHP.DisallowShortOpenTag"/>
✤   „ruleset.xml“               <rule ref="Squiz.Functions.GlobalFunction"/>

                                <!-- Lines can be 85 chars long, but never show errors
                               -->
✤   Zusammenstellung            <rule ref="Generic.Files.LineLength">
    verschiedener Sniffs         <properties>
                                   <property name="lineLimit" value="85"/>
                                   <property name="absoluteLineLimit" value="0"/>
                                 </properties>
✤   Überschreibung von          </rule>

    möglichen Konfigurationen   <!-- Use Unix newlines -->
                               <rule ref="Generic.Files.LineEndings">
                                <properties>
                                 <property name="eolChar" value="n"/>
                                </properties>
                               </rule>
                               ...
Wie sieht ein Sniff aus?

✤   PHP-Klasse implementiert „Sniff“-Interface (direkt / indirekt)

    ✤   PHP_CodeSniffer_Sniff

    ✤   PHP_CodeSniffer_Standards_AbstractVariableSniff / ...

✤   Setzt „supportedTokenizers“ (PHP, JS, CSS)

✤   Registriert verschiedene Tokens via „register()“

✤   Prüft die Regel via „process()“
Wie sieht ein Sniff aus?
class PEAR_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff {

	   public $supportedTokenizers = array('PHP');

	   public function register() {
	   	 return array(T_COMMENT);
	   }

	   public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) {
	   	 $tokens = $phpcsFile->getTokens();

	   	   if   ($tokens[$stackPtr]['content']{0} === '#') {
	   	   	    $error = 'Perl-style comments are not allowed. Use "// Comment."';
	   	   	    $error .= ' or "/* comment */" instead.';
	   	   	    $phpcsFile->addError($error, $stackPtr, 'WrongStyle');
	   	   }
	   }
}
Gibt es auch
Unit Tests?

✤   Datei für alle möglichen Fälle

    ✤   InlineCommentUnitTest.inc

✤   Angabe in welcher Zeile wie
    viele Fehler auftreten

    ✤   InlineCommentUnitTest.php
Hast du Tipps für uns?

✤   Vorhandene Sniffs nutzen

✤   Jeder Sniff nur eine Aufgabe

✤   Konfigurierbare Sniffs

✤   Nutzung der vorhandenen Klassen

✤   Von vorhandenen Sniffs lernen

✤   Test Driven Development
Wo gibt es weitere Informationen?

✤   PEAR Package: http://pear.php.net/package/PHP_CodeSniffer

✤   Blog: http://www.squizlabs.com/php-codesniffer

✤   Parsertoken: http://php.net/manual/de/tokens.php

✤   PHPHatesMe: http://www.phphatesme.com/blog/tools/statische-
    code-analyse-mit-dem-php-code-sniffer/

✤   PTI: http://www.phpsrc.org/

✤   Netbeans Plugin: http://www.whitewashing.de/blog/articles/119
Offene Fragen?
Vielen Dank

                              Merci        Dank je wel
                                       Danke     Kiitos
                               Tack
                                          Dhanyabaad
                              Vinaka
✤   für Ihre Aufmerksamkeit            Dakujem
                                                  Grazie
                              Tesekkur ederim
                                           Dankie
                               Thank you
                                                  Hvala
Verwendete Bilder

✤   Agenda: Carbon Arc @ Flickr

✤   Gibt es auch Unit Tests?: jfravel @ Flickr

✤   Offene Fragen?: Oberazzi @ Flickr

✤   Wozu ist er gut?: Bas Van Uyen @ Flickr

✤   Vokabeln: SubZeroConsciousness @ Flickr

✤   Was kann er?: cdwaldi @ Flickr

PHP_Codesniffer

  • 1.
    PHP_CodeSniffer Andy Grunwald 22. September2010, PHP Usergroup Düsseldorf / Duisburg / Krefeld
  • 2.
    Über mich ✤ Andy Grunwald ✤ Fachinformatiker: Anwendungsentwicklung ✤ wmdb Systems GmbH ✤ PHP seit 2004 ✤ Open Source Fan ✤ Chaot
  • 3.
    Agenda ✤ Was ist der PHP_CodeSniffer? ✤ Wozu ist er gut? ✤ Wo kann man Ihn einsetzen? ✤ Gibt es eigene Bezeichnungen? ✤ Gibt es fertige Standards? ✤ Was kann er? ✤ Wie funktioniert er?
  • 4.
    Agenda ✤ Was sind Tokens? ✤ Wie sieht ein Standard aus? ✤ Wie sieht ein Sniff aus? ✤ Gibt es auch Unit Tests? ✤ Hast du Tipps für uns? ✤ Wo gibt es weitere Informationen?
  • 5.
    Was ist derPHP_CodeSniffer? ✤ Tool zur statischen Code Analyse ✤ „Analysiert Dateien und erkennt Verletzungen von definierten Regeln“ ✤ PHP (, JS, CSS) Qualitätssicherungs-Tool ✤ Greg Sherwood (Product Development Manager, Squiz Labs) ✤ Vorraussetzung: PHP >= 5.1.2 + exttokenizer
  • 6.
    Was ist derPHP_CodeSniffer? ✤ BSD License ✤ PEAR-Package ✤ „Package Maintenance Rank: 4 of 202 packages“. ✤ Aktuelle Version: 1.3.0 RC1 (Stable: 1.2.2) ✤ Sehr aktives Projekt ✤ Schnelle Reaktionszeiten auf Tickets (Features / Bugs)
  • 7.
    Wozu ist ergut? ✤ SourceCode bleibt sauber und konsistent ✤ Coding Standards ✤ Bug Patterns ✤ Perfomance Patterns
  • 8.
    Wo kann manIhn einsetzen? ✤ Manuelle Analyse auf der Shell ✤ Continuous Integration-Server (Hudson, PHPUnderControl, ...) ✤ SVN-Hook(s) ✤ IDE (Eclipse via PTI, Netbeans via Plugin von Benjamin Eberlei)
  • 9.
    Gibt es eigene Bezeichnungen? ✤ „Sniff“ ✤ Eine Regel die einen bestimmten Zustand prüft ✤ „Standard“ ✤ Eine Zusammenstellung von verschiedenen Sniffs
  • 10.
    Gibt es fertigeStandards? ✤ Auflistung installierter Coding Standards: „phpcs -i“ ✤ MySource PHP_CodeSniffer ✤ PEAR ✤ PHPCS ✤ Squiz ✤ Zend
  • 11.
    Was kann er? ✤ Mit einem Standard „sniffen“ ✤ Mit bestimmten Sniffs „sniffen“ ✤ Ordner [Rekursiv] /Einzelne Datei „sniffen“ ✤ Ordner / Dateien via Pattern ignorieren ✤ Ausgabe in verschiedenen Formaten (XML, CSV, Checkstyle, ...)
  • 12.
    Wie funktioniert er? ✤ Angegebener Standard wird analysiert („register()“) ✤ Datei wird eingelesen und durch exttokenizer verarbeitet ✤ Tokens werden durchlaufen ✤ Sniff („process()“) wird bei registriertem Token aufgerufen ✤ Fehler werden gesammelt und ausgegeben
  • 13.
    Was sind Tokens? ✤ Teilung von Sprachkonstrukten / SourceCode in einzelne Zeichen
  • 14.
    Was sind Tokens? T_CONTINUE T_DO T_ISSET T_NEW T_SWITCH ✤ Teilung von T_FOREACH T_CLASS Sprachkonstrukten / SourceCode in einzelne Zeichen T_BOOLEAN_AND T_PUBLIC T_PRIVAT T_CATCH T_WHILE T_EVAL
  • 15.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ?>
  • 16.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ?>
  • 17.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ?> ✤ T_OPEN_TAG
  • 18.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ?>
  • 19.
    Was sind Tokens? <?php function foo($bar){ ✤ T_FUNCTION return ($bar + 1); T_WHITESPACE } T_STRING T_OPEN_PARENTHESIS ?> T_VARIABLE T_CLOSE_PARENTHESIS T_OPEN_CURLY_BRACKET T_WHITESPACE
  • 20.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ?>
  • 21.
    Was sind Tokens? <?php ✤ T_WHITESPACE T_RETURN function foo($bar){ T_WHITESPACE return ($bar + 1); T_OPEN_PARENTHESIS } T_VARIABLE T_WHITESPACE ?> T_PLUS T_WHITESPACE T_LNUMBER T_CLOSE_PARENTHESIS T_SEMICOLON T_WHITESPACE
  • 22.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ?>
  • 23.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ✤ T_CLOSE_CURLY_BRACKET ?> T_WHITESPACE
  • 24.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ?>
  • 25.
    Was sind Tokens? <?php function foo($bar){ return ($bar + 1); } ?> ✤ T_CLOSE_TAG
  • 26.
    Was sind Tokens? [type] => T_STRING ✤ Code: Wert der Konstante [code] => 307 [content] => foo ✤ Type: Konstantenname [line] => 2 [column] => 10 ✤ Content: Realer Content [code] => 370 ✤ Line: Zeilennummer [content] => ?> [type] => T_CLOSE_TAG ✤ Column: Zeichenanzahl [line] => 5 [column] => 1
  • 27.
    Wie sieht ein Standardaus? ✤ Standard-Konfiguration ✤ ruleset.xml ✤ FooCodingStandard.php ✤ Dokumentation ✤ Sniffs nach Kategorien ✤ Unit Tests nach Kategorien
  • 28.
    Wie sieht einStandard aus? <?xml version="1.0"?> <ruleset name="PEAR"> <description>The PEAR coding standard.</description> <!-- Include some additional sniffs from the Generic / PEAR standard --> <rule ref="Generic.PHP.DisallowShortOpenTag"/> ✤ „ruleset.xml“ <rule ref="Squiz.Functions.GlobalFunction"/> <!-- Lines can be 85 chars long, but never show errors --> ✤ Zusammenstellung <rule ref="Generic.Files.LineLength"> verschiedener Sniffs <properties> <property name="lineLimit" value="85"/> <property name="absoluteLineLimit" value="0"/> </properties> ✤ Überschreibung von </rule> möglichen Konfigurationen <!-- Use Unix newlines --> <rule ref="Generic.Files.LineEndings"> <properties> <property name="eolChar" value="n"/> </properties> </rule> ...
  • 29.
    Wie sieht einSniff aus? ✤ PHP-Klasse implementiert „Sniff“-Interface (direkt / indirekt) ✤ PHP_CodeSniffer_Sniff ✤ PHP_CodeSniffer_Standards_AbstractVariableSniff / ... ✤ Setzt „supportedTokenizers“ (PHP, JS, CSS) ✤ Registriert verschiedene Tokens via „register()“ ✤ Prüft die Regel via „process()“
  • 30.
    Wie sieht einSniff aus? class PEAR_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff { public $supportedTokenizers = array('PHP'); public function register() { return array(T_COMMENT); } public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['content']{0} === '#') { $error = 'Perl-style comments are not allowed. Use "// Comment."'; $error .= ' or "/* comment */" instead.'; $phpcsFile->addError($error, $stackPtr, 'WrongStyle'); } } }
  • 31.
    Gibt es auch UnitTests? ✤ Datei für alle möglichen Fälle ✤ InlineCommentUnitTest.inc ✤ Angabe in welcher Zeile wie viele Fehler auftreten ✤ InlineCommentUnitTest.php
  • 32.
    Hast du Tippsfür uns? ✤ Vorhandene Sniffs nutzen ✤ Jeder Sniff nur eine Aufgabe ✤ Konfigurierbare Sniffs ✤ Nutzung der vorhandenen Klassen ✤ Von vorhandenen Sniffs lernen ✤ Test Driven Development
  • 33.
    Wo gibt esweitere Informationen? ✤ PEAR Package: http://pear.php.net/package/PHP_CodeSniffer ✤ Blog: http://www.squizlabs.com/php-codesniffer ✤ Parsertoken: http://php.net/manual/de/tokens.php ✤ PHPHatesMe: http://www.phphatesme.com/blog/tools/statische- code-analyse-mit-dem-php-code-sniffer/ ✤ PTI: http://www.phpsrc.org/ ✤ Netbeans Plugin: http://www.whitewashing.de/blog/articles/119
  • 34.
  • 35.
    Vielen Dank Merci Dank je wel Danke Kiitos Tack Dhanyabaad Vinaka ✤ für Ihre Aufmerksamkeit Dakujem Grazie Tesekkur ederim Dankie Thank you Hvala
  • 36.
    Verwendete Bilder ✤ Agenda: Carbon Arc @ Flickr ✤ Gibt es auch Unit Tests?: jfravel @ Flickr ✤ Offene Fragen?: Oberazzi @ Flickr ✤ Wozu ist er gut?: Bas Van Uyen @ Flickr ✤ Vokabeln: SubZeroConsciousness @ Flickr ✤ Was kann er?: cdwaldi @ Flickr