PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Script zur Entfernung von schliessenden PHP Tags

with 29 comments

Nach wie vor gibt es viele Diskussionen ob das schliessende PHP-Tag am Ende einer PHP-Datei weggelassen werden sollte oder nicht. In vielen großen Projekten wird das Weglassen mittlerweile vorgeschrieben (Zend Framework, Symfony, Doctrine), in einigen muss es zwingend vorhanden sein (Lithium), aber in noch mehr Projekten ist es nicht festgelegt und wird mal weggelassen mal eingefügt, je nachdem welcher Entwickler die Datei erstellt bzw. als letztes geändert hat.

Besonders in Projekten mit gemischtem Vorgehen sollte eine einheitliche Lösung gefunden werden, und falls das die Löschung der End Tags bedeutet, dann nutze ich mein kleines Script hier um alle Dateien von schliessenden PHP Tags am Ende zu befreien:

<?php

if ($argc == 2) {
    $path = $argv[1];
} else {
    $path = '.';
}

// find all .php files recursively
$files = array();

$Directory = new RecursiveDirectoryIterator($path);
$Iterator = new RecursiveIteratorIterator($Directory);
$Regex = new RegexIterator($Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH);
foreach ($Regex as $r) {
    $files[] = $r[0];
}

echo "Starting to process ".count($files)." files.\n";

foreach ($files as $file) {
    $content = file_get_contents($file);

    // if there are no end tags, don't do anything
    if (strpos($content, '?>') === false) {
        echo "skipping because there are no end tag: $file\n";
        continue;
    }

    preg_match_all('/\?\>/', $content, $matches);
    if (count($matches[0]) > 1) {
        echo "skipping because of >1 end tags found, maybe not a php-only file: $file\n";
        continue;
    }

    $newContent = rtrim($content);
    $newContent = preg_replace('/\?\>$/', '', $newContent, -1, $count);
    if ($count == 1) {
        $newContent = rtrim($newContent);
        $newContent .= "\n";

        file_put_contents($file, $newContent);

        echo "fixed file: $file\n";
        continue;
    } else {
        echo "skipping because the end tag is not at the end of the file: $file\n";
        continue;
    }
}

Ein Beispielaufruf steht in der README im GitHub Projekt, es gibt nur einen optionalen Parameter: Das Verzeichnis. Falls der Parameter nicht angegeben wird wird das aktuelle Verzeichnis genommen.

Das Script ist nicht perfekt und aktuell nicht für Projekte geeignet die mit Windows-Umbrüchen arbeiten, aber bisher hat es mir gute Dienste geleistet. Wer Lust hat kann es gern noch um die angesprochene Windows-Umbruch-Unterstützung erweitern oder anders verbessern, man kann sicher mit einem komplizierteren Regex arbeiten und sich die rtrim()s sparen. Würd mich sehr freuen.

Ich habe auch ein schönes kurzes Bash-Script gefunden, das aber nur auf Unix-Rechnern mit installiertem pcregrep, awk, wc und sed funktioniert, und genau das selbe tut.

Written by Michael Kliewe

März 28th, 2012 at 10:12 am

29 Responses to 'Script zur Entfernung von schliessenden PHP Tags'

Subscribe to comments with RSS or TrackBack to 'Script zur Entfernung von schliessenden PHP Tags'.

  1. Gibt es einen Sinn, wieso man diese weglässt? Also ich meine einen anderen außer das Sparen von 2 Bytes (mit Umbruch 3-4).

    IcyT

    28 Mrz 12 at 10:31

  2. @IcyT Gibt es denn einen Sinn sie nicht weg zu lassen? 😉

    @Michael Wieso entfernst du es nicht, wenn es mehr als einmal vorkommt? Man könnte ja dann schauen ob danach noch Text kommt und wenn nicht das letzte entfernen.

    Patrick

    28 Mrz 12 at 10:49

  3. @lcyT: Ja des öfteren passiert es dass nach dem schliessendem Tag noch Whitespaces vorhanden sind – und diese somit ausgegeben werden. Wie oft das tatsächlich passiert ist fraglich – ich hatte jedoch schon Projekte bei denen es der Fall war.

    808

    28 Mrz 12 at 10:52

  4. @808: Danke, das lasse ich als Argument durchgehen 🙂

    IcyT

    28 Mrz 12 at 10:55

  5. Ja die Whitespaces am Ende der Datei können einem schon mal den Tag versauen. Insbesondere wenn man komische „Cannot modify header information“ Fehler sieht.

    Aber auf der anderen Seite lässt man aber auch nicht die schließende geschweifte Klammer weg.

    Vielleicht kommen wir ja auch mal in den Zustand, dass der öffnende PHP Tag überflüssig wird. Und dann lösche ich auch gerne den schließenden 🙂

    Norbert

    28 Mrz 12 at 11:25

  6. @Patrick: Die meisten Coding Standards schreiben das Entfernen nur bei „PHP-only“ Dateien vor, sprich Klassen etc. Wie das generell bei gemischten Dateien ist weiß ich nicht, man könnte sie natürlich auch dort entfernen. Aber ich lasse sie da so wie sie sind, möchte ja nichts falsch korrigieren. Wenn man die Prüfung auskommentiert sollten sie auch dort entfernt werden. Wäre natürlich cool wenn man sowas via Kommandozeilen-Parameter steuern könnte. Ein „dry-Modus“ wäre auch cool, dann wird einem erstmal angezeigt was geändert werden würde, dann kann man kurz drübergucken ob alles korrekt ist bevor man die Änderungen an den Dateien macht.

    Michael Kliewe

    28 Mrz 12 at 11:28

  7. Das Whitespace Problem habe ich leider auch in einem Project, an der Stelle stört es nicht weiter, trotzdem würde ich es gerne entfernen. Gibt es hier auch einen Weg, wie man die betroffenen Dateien finden kann ?
    Den PHP Tag, wie mit diesem Skript zu entfernen, ist leider keine Option.

    sven

    28 Mrz 12 at 11:35

  8. @sven: In der aktuellen EAP Version (Early Access Programm; quasi alpha-Version) von PHPStorm 4 gibt es eine neue Code Inspection: „Code-Style -> Redundant closing tag“. Damit kann man sich die überflüssigen schliessenden Tags anzeigen lassen denk ich mal.

    Download EAP:
    http://confluence.jetbrains.net/display/WI/Web+IDE+EAP

    Michael Kliewe

    28 Mrz 12 at 12:06

  9. @Michael: Ich denke es geht sven darum das Leerzeichen zu finden und nicht die redundanten Closing Tags.

    @sven: Kannst du nicht einfach mit einem regulären Ausdruck alle Closing Tags suchen, die danach noch ein \n bzw. ein \r\n haben?

    IcyT

    28 Mrz 12 at 12:34

  10. @IceT: EIN \n bzw. \r\n ist (jeweils) nach dem schließenden bzw öffnenden Tag erlaubt 😉

    $ php -r „var_dump(token_get_all(\“\r\n\“));“

    Das muss man noch bei seinem Regex beachten. Wenn man einigermaßen sauber war, muss man aber wenigstens nicht \n UND \r\n berücksichtigen :3

    KingCrunch

    28 Mrz 12 at 13:28

  11. @Patrick: Die PHP-Tags sind genau genommen XML Processing Instructions, jedenfalls der Syntax nach. Im Gegensatz zu ASP, das mit arbeitet, sind sie damit auch innerhalb von XML- und XHTML-Dateien vollkommen valide (was diverse HTML-Validatoren nicht unbedingt so sehen müssen, aber das ist deren Problem). Allerdings sind sie nur so lange valide, wie sie auch wieder geschlossen werden.

    Das heißt grundsätzlich, dass das Entfernen des schließenden Tags immer zu invalidem Code führt – vorausgesetzt man nimmt es genau.

    Das Entfernen aus dem Grund, den @808 beschreibt, ist somit nicht die Lösung des Problems, sondern nur ein Workaround für all die Schlamper da draußen, die es nicht gebacken kriegen, den überflüssigen Whitespace am Ende zu entfernen. Manchmal sind es auch die dämlichen IDEs, die der Meinung sind, unbedingt am Ende noch einen Umbruch machen zu müssen. Mit anderen Worten: jedes Mal, wenn jemand den schließenden Tag weg lässt, stirbt irgendwo auf der Welt ein Kätzchen. Oder: Wer den schließenden Tag weglässt, rückt auch mit Leerzeichen ein.

    Natürlich funktioniert jede Lösung dieses Problems, aber wenn man es genau nimmt, ist der einzig richtige Weg, den Tag zu schließen und danach keinen Whitespace mehr zu haben.

    Ich würde mir auch wünschen, dass PHP in der Lage ist, ganz ohne die Tags auszukommen, wenn eine Datei nichts anders als PHP-Code enthält. Das würde uns in diesem Fall ziemlich weiter bringen.

    Um auch noch was zum eigentlichen Thema zu sagen: Finde das Script gut und nützlich, wenn man durch die blöden Regeln von Zend dazu genötigt wird, invaliden Code zu schreiben.

    Bert

    28 Mrz 12 at 13:36

  12. >Wer den schließenden Tag weglässt,
    > rückt auch mit Leerzeichen ein.
    Ich schreibe i.d.R. nicht mehr als 80 Zeichen in eine Zeile.
    Bei 79 einrückenden Leerzeichen, gefolgt von einer schliessenden Klammer, schaut mein Programmcode auch mit less und vim noch übersichtlich aus.
    Was spricht gegen Leerzeichen?

    Patrick-Oliver

    28 Mrz 12 at 16:32

  13. Ich bin der gleichen Meinung wie Bert, schließende Tags gehören für mich dazu und ein weglassen dieser unterstützt nur die Schlamper unter uns Entwicklern.

    Maximilian Kern

    28 Mrz 12 at 16:59

  14. @Michael, @IcyT, @KingCrunch

    Ja, ich muss leider Whitespaces entfernen und habe bisher auch noch keine vernünftige regex hinbekommen die mir das gesuchte ausgegeben hat.
    Da es sich auch noch um ein CMS mit einigen Erweiterungen handelt, macht das ganze leider nicht einfacher. Zudem ist es auch noch ein WindowsServer, waren hier nich die Umbrüche anders ?

    Doch vielen Dank schon mal 🙂

    sven

    28 Mrz 12 at 17:31

  15. Lustig, wie hier scheinbar viele Leute Probleme mit Whitespace am Dateiende haben – ist mir in über 14 Jahren PHP-Programmierung nicht als Problem aufgefallen. Und so diskutiert das halbe PHP-Netz über Probleme, die man scheinbar eh nur hat, wenn man schlechte IDEs benutzt oder einfach unaufmerksam ist…

    Philipp

    28 Mrz 12 at 18:33

  16. Mit ein bisschen Bash wäre das einiges weniger Code gewesen. 😉

    Fabian

    28 Mrz 12 at 19:25

  17. @Patrick-Oliver: Wenn jemand gegen Leerzeichen zum Einrücken argumentiert, kommt normalerweise immer „das verbraucht mehr Speicherplatz“. Das ist zwar richtig, aber höchstens bei HTML und XML von Bedeutung.

    Das eigentliche Problem bei Leerzeichen gegenüber Tabs ist, dass es dem Entwickler die Möglichkeit nimmt, die Tiefe der Einrückung selbst zu bestimmen. Ich stelle die Einrückung gerne so ein, dass ein Tab 4 Zeichen entspricht. Meine Kollegen mögen lieber 2, 3 oder 6 Zeichen tiefe Einrückungen. Wenn man Tabs verwendet, kann jeder den Code mit der Einrückungstiefe lesen, die ihm gefällt. Verwendet man Leerzeichen, ist alles fix und somit für manche Entwickler ungewohnt und unübersichtlich.

    Bert

    28 Mrz 12 at 20:44

  18. Probleme kenne ich nur durch UTF-8 BOM am Anfang der Datei. Welches gerne auch mal von einer IDE eingefügt wird/wurde. Ob nun “Coding Standards” dazu Vorgaben machen, ist auch ein wenig Geschmacksache. Notwendig ist dies eigentlich nicht. Gegen “Cannot modify header information” hilft ob_start() da wesentlich besser 😉
    Das “Coding Standards” oft mehr auf “Einheitlichkeit” abzielen, anstatt “besser” oder “logisch” zu sein, zeigt für mich das völlig unverständliche
    function x()
    {
    // some code
    }

    (Die Begrenzer eines Codeblocks sind ausserhalb befinden sich ausserhalb des Blocks …)

    Thorsten

    28 Mrz 12 at 22:35

  19. Ich stimme auch Bert zu, wo was geöffnet wird, da muss es auch geschlossen werden, sonst ist es nicht valide und kann irgendwann zu Problemen führen.

    @Thorsten
    Einrücken nach Allman/K&R/etc. finde ich sehr sinnig und übersichtlich, aus den einfachen Grund die öffenende Klammer ist auf einer höhe mit der schließenden Klammer. Und dabei finde ich es persönlich besser als andere Coding Standards, da finde ich die Begrenzer schnell und ohne Problem und muss nich erst ein paar Meter nach rechts Scrollen, um ggf. den Begrenzer neben den anderen Zeichen zu finden.

    Klar könnte man auch nach Horstmann, nur das empfinde ich persönlich als sehr irritierend und nebenher haben einige Version Control Systeme haben damit Schwierigkeiten.

    Und ich bin froh meinen Stil vor 2 Jahren gewechselt zu haben, und empfinde das Arbeiten nun im Programmcode um einiges angenehmer.

    Also was Du als unlogisch und schlechter empfindest, empfinden andere als „besser“ und „logischer“.

    Sascha Ahlers

    29 Mrz 12 at 09:29

  20. @Bert: Ich rücke mit Tabs ein, weil Einrückung mittels Leerzeichen objektiv gesehen unsinnig ist. Außer natürlich, der Coding Standard schreibt es vor, dann unterwerfe ich mich. Dennoch lasse ich das End-Tag weg. Dass es sich eigentlich um eine XML-Processing-Anweisung handelt, hat höchstens historische bzw. informelle Bedeutung. Das Weglassen in Dateien, die nur (bis auf das Start-Tag) PHP-Code enthalten, wird sogar in der Anleitung empfohlen.

    @Patrick-Oliver: less -x 1 😉

    @Sascha Ahlers: Die schließenden und öffnenden Klammern sind reiner „Noise“ und tragen beim Lesen, was man mit Code nunmal sehr häufig macht, nichts zum Verständnis bei – die Struktur ergibt sich ja schon durch die Einrückung. Ich präferiere daher einen Coding-Style, bei dem die öffnende Klammer hinten an der öffnenden Zeile ist und die schließende Klammer hinten an der letzten Zeile des Blocks.

    GodsBoss

    29 Mrz 12 at 20:25

  21. @Bert:
    Ungeachtet der Sinnhaftigkeit, wie schreibt man dann folgendes mit Tabs?

    $foo = ‚Hallo ‚
    . ‚Welt‘;

    Vor dem „. ‚Welt‘;“ sind – in Abhängigkeit des Variablennamen $foo – fünf Leerzeichen eingefügt.
    Der nächste Variablenname ist möglicherweise breiter als fünf Zeichen, also stehen Texte nicht immer, wie ggf. gefordert, übereinander.

    Bei aller Liebe. Wenn Programmcode formatiert wird, dann so, dass er auf ALLEN Maschinen gleich ausschaut.
    Und individuale Formatierungswünsche werden beim Festlegen der Coding-Standards berücksichtigt (oder auch nicht *g*), nicht am Arbeitsplatz.

    Meine Meinung! 😉

    Btw. imo ist vernünftig strukturierter Quelltext immer les- und wartbar.
    Mir ist dabei egal ob mit Tabs oder Leerzeichen eingerückt wurde.
    Ich will einfach nur nicht hinnehmen, dass gesagt wird: „Alle, die anders arbeiten als ich, sind doof“.

    @GodsBoss
    Als durchschnittlich dummer Mensch empfinde ich Einrückungen mit Tabs subjektiv als unsinnig.
    Dass ich eine mir zugewiesene Arbeitsumgebung an z.B. deine Tab-Einstellung anpassen muss, nur damit ich Quelltext in der von dir vorgesehenen Textformatierung vorliegen habe … ?
    Tolle „Coding-Standards“ sind das, wenn jeder seine Suppe kocht.
    Noch unsinniger finde ich es, solche Dinge zu pauschalisieren.

    Ich bleib dabei, bezüglich Textformatierungen sind Leerzeichen für mich mindestens eine Alternative zu Tabs.

    Btw. auch ich lasse schließende PHP-Tags weg.
    So ist immer am Ende auch Ende 🙂
    Nachteile? Sind mir nicht bekannt.

    Patrick-Oliver

    30 Mrz 12 at 09:02

  22. Autsch, die fünf Leerzeichen vor „. ‚Welt'“ muss man sich hier dazu denken.

    Patrick-Oliver

    30 Mrz 12 at 09:05

  23. Juuhuu habe endlich die Antwort auf meine Lösung gefunden! Danke! 🙂

    Heilungsmaus

    30 Mrz 12 at 21:20

  24. @Patrick-Oliver:
    Verstehe nicht, was du meinst. Eingerückt wird bei Tabs, zumindest kenne ich das so, grundsätzlich mit einem Tab pro Schachtelungstiefe. Wieviel Zeichen ein Tab am Ende breit ist, entscheidet dann jeder selbst.

    Wohlgemerkt, damit es nicht zu Missverständnissen kommt: Zur Einrückung, nicht zur Ausrichtung (wobei ich, wenn ich die Wahl habe, auf Ausrichtung in der Regel verzichte).

    GodsBoss

    30 Mrz 12 at 22:29

  25. > Wohlgemerkt, damit es nicht zu Missverständnissen kommt: Zur Einrückung, nicht zur Ausrichtung (wobei ich, wenn ich die Wahl habe, auf Ausrichtung in der Regel verzichte).

    Vermutlich weil eben Ausrichtung mit Tabs nie funktioniert. Mit Leerzeichen schon 😉

    Zum Thema: PHP-Tags dienen zum Abgrenzen von Code und Markup und der Benefit ergibt sich beim Include von anderen Scripten. Nun ist der Include-Mechanismus aber so angelegt, dass er automatisch im Markup-Modus beginnt und endet. Folglich verstehe ich die Argumentation gegen das Weglassen nicht. Es bietet einen Vorteil und gäbe es eine Lösung, das BOM auch noch kassieren lassen zu können – ich würde sie nutzen. Auch wenn ich kein Schlamper diesbzegl. bin, ich erlebe genaug Leute, die immer wieder über header sent stolpern. Da finde ich die Ouput-Buffer-Lösung viel grottiger.

    Den Code finde ich etwas lang geraten, ich würde es wohl auf

    $newContent = preg_replace('/\?>\s*$/', '', $newContent, -1, $count);
    if (PREG_NO_ERROR === preg_last_error() && 1 == $count) {
    // copy
    // write back
    }

    beschränken.

    nk

    9 Jul 12 at 20:31

  26. @nk:
    „Vermutlich weil eben Ausrichtung mit Tabs nie funktioniert. Mit Leerzeichen schon ;)“
    Nein, nicht deswegen. Leerzeichen benutze ich durchaus. Nur nicht zur Einrückung. 😉 Ich richte deswegen selten Code aus, weil ich dafür meist (aber nicht immer) keine Notwendigkeit sehe.

    GodsBoss

    9 Jul 12 at 20:51

  27. Da die Sache recht wiedersprüchlich behandelt wird, sollte doch wohl für PHP eine einheitliche Regelung eingeführt werden. Ist die Regel vorgegeben müssen sich alle daran halten, und diese Diskussion ist überflüssig, wir können uns wieder den eigentlichen Problemen unserer Arbeit zuwenden und müssen nicht unsere kostbare Zeit mit so unwichtigen Dingen verbringen, ob das schliessende PHP Tag am Ende des Scripts wirklich eine elementare Bedeutung hat.
    Damit verdiene ich kein Geld.

    Andreas Groß

    21 Aug 12 at 00:50

  28. Ich finde es zugegeben etwas amüsant, dass man den schließenden PHP-Tag hier automatisch entfernen lässt. Wenn man schon mit einem solchen Mechanismus arbeitet, wäre es dann nicht um einiges sinnvoller, einfach die überflüssigen Whitespaces nach dem Tag zu entfernen? Diese sind doch schließlich das eigentliche Problem, oder?

    Lars Ebert

    23 Apr 13 at 11:29

  29. @Lars: Das ist zwar richtig, aber das schließende Tag erfüllt definitiv keine sinnvolle technische Aufgabe. Wenn man alles beachtet, bietet es zwar keinen wirklichen Nachteil, aber eben auch keinen Vorteil.

    Einen Nachteil hat es übrigens, was Tools angeht: Das Versionsverwaltungssystem git merkt grundsätzlich an, wenn eine Textdatei nicht mit einer leeren Zeile endet. Kann man eventuell abschalten, aber es ist definitiv die Standard-Einstellung. Mit schließendem Tag nervt das, weil ich da nunmal keinen Zeilenumbruch mehr machen darf (ohne Probleme zu bekommen), ohne hingegen kein Problem.

    GodsBoss

    23 Apr 13 at 13:16

Leave a Reply

You can add images to your comment by clicking here.