• PHP Code Sniffer – Funtionsweise

    von am 12. März 2009

    Mit dem vierten Tag kommen wir auch wohl zum komplexesten Thema: dem Erstellen eigener Regeln. Wie ich ja schon erzählt habe ist auch für mich dies Thema Neuland, seht diesen Artikel also eher als Live-Bericht. Bevor wir uns aber eine Regel ausdenken, der wir und dann widmen wollen, schauen wir uns doch einfach eine existierende Regeln an und beschreiben mal kurz, was dort passiert. Danach versuche ich kurz die generelle Funktionsweise eines Sniffs zu erläutern und dann nehmen wir uns eine eigene Regel, die wie dann implementieren und unserem Regelset hinzufügen. Was dies für eine Regel sein wird, weiß ich jetzt noch nicht, aber ich habe ja noch den ganzen Tag Zeit.

    Fangen wir also mit einer existierenden Regeln an. Ich habe mich für den Generic_Sniffs_PHP_LowerCaseConstantSniff Sniff entschieden, da ich denke, dass die paar Zeilen, die er beinhaltet einen guten Einstieg zulassen. Vielleicht noch kurz vorne weg: der Sniff sorgt “lediglich” dafür, dass null, true und false klein geschrieben werden.

    class Generic_Sniffs_PHP_LowerCaseConstantSniff implements PHP_CodeSniffer_Sniff
    {
        public $supportedTokenizers = array(
                                       'PHP',
                                       'JS',
                                      );
    
        public function register()
        {
            return array(
                    T_TRUE,
                    T_FALSE,
                    T_NULL,
                   );
        }
    
        public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
        {
            $tokens = $phpcsFile->getTokens();
    
            $keyword = $tokens[$stackPtr]['content'];
            if (strtolower($keyword) !== $keyword) {
                $error = 'TRUE, FALSE and NULL must be lowercase; expected "'.strtolower($keyword)
                        .'" but found "'.$keyword.'"';
                $phpcsFile->addError($error, $stackPtr);
            }
        }
    }

    Obwohl dieses Beispiel recht simpel ist, beschreibt es doch bereits alles, was wir brauchen. Nehmen wir und erst mal das Interface vor, gegen das wir implementieren müssen. Da dies recht simpel ist und nur zwei öffentlichen Methoden besteht, schauen wir es uns einfach mal an.

    interface PHP_CodeSniffer_Sniff
    {
        public function register();
        public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr);
    }

    Vielleicht haben einige von euch schon ein grobes Bild gewonnen über die Funktionsweise, wenn sie dieses Interface anschauen. Wir wollen aber trotzdem noch mal kurz abschweifen und die generelle Vorgehensweise des Code Sniffers beschreiben.

    Vorgehensweise des Code Sniffers

    Will man eigene Regeln schreiben, so muss das Verständnis für die Funktionsweise des Code Sniffers existieren. Prinzipiell geht der Sniffer immer gleich vor. Er zerlegt den zu analysierenden Code in sogenannte Tokens (was der PHP Interpretor übrigens nicht anders macht), also in logisch zusammenhängende Einheiten. Dies können zum Beispiel normale (T_COMMENT) bzw. PHPDoc (T_DOC_COMMENT) Kommentare sein, aber auch true (T_TRUE) entspricht einem Token.

    Wie man sich vorstellen kann, gibt es jede Menge Tokens. Aus diesem Grund werde ich sie hier auch nicht alle aufzählen. Ob es eine vollständige Liste mit Erläuterungen irgendwo im Netzt gibt, weiß ich leider nicht. Ich kann aber die Klasse PHP_CodeSniffer_Tokens im Hauptverzeichnis empfehlen, da hier die Tokens alle aufgelistet wurden und auch nach Themen gruppiert sind. Mit diesem Wissen können wir jetzt anfangen uns noch mal das Interface anschauen.
    Die register Methode wird dazu verwendet zu definieren, auf welchen Tokens der Sniff losgelassen werden soll. Hier müssen wir einfach nur einen Array zurück geben, wie zum Beispiel array( T_TRUE, T_FALSE, T_NULL ) (wir erinnern und an unser Beispiel).Haben wir erstmal unseren Gültigkeitsbereich definiert, so springt der Sniffer jedes mal, wenn er über ein registriertes Token stolpert in die Methode process, mit den aktuellen Zustandsinformationen. Hier sind wir auch schon bei der zweiten und letzen Methode des Interfaces angekommen. Die Funktion bekommt zwei Parameter, der erste $phpcsFile hält alle Informationen über das ganze Dokument, das gerade untersucht wird. Der zweite $stackPtr entspricht der Stelle, an der sich der Parser gerade befindet, also der Stelle an dem das registrierte Token gefunden wurde. Mit diesem Wissen, sind wir nun in der Lage rauszufinden, was vor uns nach unserem Token passiert, was in unserem einfachen Beispiel von oben ja nicht wirklich relevant ist, da wir uns nur das Token ansehen und prüfen ob es nicht komplett klein geschrieben wurde.

    Ich hoffe, dass mit diesem Hintergrundwissen das einfache Beispiel von oben allen klar sein sollte, dennoch möchte ich so eine Liste von Tokens präsentieren, wie sie PCS erstellt. Folgender Code (nur der Code in der Funktion)

    public function uninitialized_assignement( )
    {
      $test1 = 1;
    }

    Sieht in Tokens zerlegt so aus:

    T_OPEN_CURLY_BRACKET
    T_WHITESPACE
    T_WHITESPACE
    T_VARIABLE
    T_WHITESPACE
    T_EQUAL
    T_WHITESPACE
    T_LNUMBER
    T_SEMICOLON
    T_WHITESPACE
    T_WHITESPACE
    T_CLOSE_CURLY_BRACKET

    Natürlich hat sie ein Token noch mehr Informationen,als nur den Typ, aber da gehen wir später noch drauf ein. Da ich mich schon wieder “verquatscht” habe, werden wir morgen weiter machen mit der ersten selbst geschriebenen Regel. Wir fangen mit einer an, die prüft ob ein Klassenname einem Bestimmten regulären Ausdruck genügt.

    Nils Langner

    Auch wenn Ihr es mir nicht glauben werdet, aber ich habe nichts gegen PHP. Ich rege mich einfach nur gerne auf. Ok so schlimm ist es auch nicht. Eigentlich wollte ich schon immer einen Blog haben und da ...

    Zum Profil von Nils Langner

    3 Kommentare »


    • Tobias
      am 12. März 2009 um 17:42 Uhr

      Na du scheinst dich ja nicht sonderlich gut auf den Artikel vorbereitet zu haben :-P

      Die genannten Tokens sind von dem PHP-Tokenizer und kann man hier einsehen:
      http://www.php.net/manual/en/tokens.php


    • admin
      am 12. März 2009 um 20:24 Uhr

      @Tobias: Das hast du ja schön gesagt. Trotzdem danke.


    • PHP hates me - Der PHP Blog » PHP Code Sniffer - Eigene Regeln erstellen
      am 13. März 2009 um 12:16 Uhr

      [...] bin ja in den letzten Artikeln schon drauf eingegangen wie process funktioniert, was wir als erstes tun müssen ist rauszufinden, [...]

    RSS Feed für Kommentare zu diesem Artikel. TrackBack URL

    Hinterlasse einen Kommentar

    Werbung
    PHP Magazin
    Ausgabe 02/2010

    Dieses Mal mit Artikeln zu den Themen OpenSocial und Apache Shindig, Graphentheorie, Smarty3

    t3n
    Ausgabe 19

    Social Media (R)evolution. Weitere Themen sind noSQL, Crowdsourcing ...

    PHP Journal
    Ausgabe 2/2010

    PHP & Windows optimal nutzen, die besten PHP-CMS im Überblick, Google-API mit Zend Framework nutzen.

    Wir wurden schon öfters gefragt, ob man uns nicht irgendwie unterstützen kann. Die Antwort war immer einfach: Klar! Am einfachsten ist es eure nächsten Einkäufe bei Amazon über unsere Link abzuwickeln. Damit würdet ihr uns schon sehr helfen. Über Co-Autoren freuen wir uns aber noch mehr.