Facebook
Twitter
Google+
Kommentare
3

PHP Code Sniffer – Funtionsweise

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.

Über den Autor

Nils Langner

Nils Langner ist der Gründer von "the web hates me" und auch der Hauptautor. Im wahren Leben leitet er das Qualitätsmanagementteam im Gruner+Jahr-Digitalbereich und ist somit für Seiten wie stern.de, eltern.de und gala.de aus Qualitätssicht verantwortlich. Nils schreibt seit den Anfängen von phphatesme, welches er ebenfalls gegründet hat, nicht nur für diverse Blogs, sondern auch für Fachmagazine, wie das PHP Magazin, die t3n, die c't oder die iX. Nebenbei ist er noch ein gern gesehener Sprecher auf Konferenzen. Herr Langner schreibt die Texte über sich gerne in der dritten Form.
Kommentare

3 Comments

Leave a Comment.

Link erfolgreich vorgeschlagen.

Vielen Dank, dass du einen Link vorgeschlagen hast. Wir werden ihn sobald wie möglich prüfen. Schließen