Gibt es einen anständigen PHP-Parser, der in PHP geschrieben ist? [geschlossen]

80

Ich arbeite viel daran, PHP-Code zu manipulieren und zu analysieren. Normalerweise benutze ich dazu nur den Tokenizer . Für die meisten Anwendungen ist dies ausreichend. Aber manchmal ist das Parsen mit einem Lexer (offensichtlich) einfach nicht zuverlässig genug.

Daher suche ich nach einem in PHP geschriebenen PHP-Parser. Ich habe hnw / PhpParser und kumatch / stagehand-php- parser gefunden . Beide werden durch eine automatisierte Konvertierung von zend_language_parser.y in eine .y-Datei mit PHP anstelle von C erstellt (und dann in einen LALR (1) -Parser kompiliert). Mit dieser automatisierten Konvertierung kann jedoch nicht gearbeitet werden.

Gibt es einen anständigen PHP-Parser, der in PHP geschrieben ist? (Ich brauche eine für PHP 5.2 und eine für 5.3. Aber nur eine davon wäre auch ein guter Ausgangspunkt.)

NikiC
quelle
1
Was ist dein Ziel? Was versuchst du hier zu erreichen?
Charles
3
@ Charles: Es gibt viele Dinge, für die ich das verwenden würde. Nur alles, was einen PHP-Quellcode in einer AST-Darstellung benötigt;)
NikiC
1
@ Mario: Das lässt viele Infos fallen. Es ist wirklich nur für die Aufgabe gedacht, einige Informationen über die Datei zu extrahieren. Es werden also nur Klassenanweisungen, Methodenanweisungen oder Rückgabeanweisungen beibehalten, aber alles ignoriert, was mich eigentlich am meisten interessiert: Der Code.
NikiC
2
Ich glaube nicht, dass Sie große, robuste Sprachparser finden werden, die in PHP codiert sind. Es gibt einfach keinen Anruf dafür.
Ira Baxter
4
In der letzten Woche habe ich selbst eine erste Version eines Parsers geschrieben: github.com/nikic/PHP-Parser Ich habe sie gegen meine Codebasis getestet und sie hat gut funktioniert. Ich werde daran arbeiten, die Schnittstellen so zu verbessern, dass sie tatsächlich verwendet werden können.
NikiC

Antworten:

128

Nachdem hier kein vollständiger und stabiler Parser gefunden wurde, habe ich beschlossen, selbst einen zu schreiben. Hier ist das Ergebnis:

PHP-Parser : Ein in PHP geschriebener PHP-Parser

Das Projekt unterstützt Parsing-Code, der für jede PHP-Version zwischen PHP 5.2 und PHP 7.1 geschrieben wurde.

Neben dem Parser selbst bietet die Bibliothek einige verwandte Komponenten:

  • Zusammenstellung des AST zurück zu PHP ("Pretty Printing")
  • Infrastruktur zum Durchlaufen und Ändern des AST
  • Serialisierung zu und von XML (sowie Dumping in einer für Menschen lesbaren Form)
  • Auflösung von Namen mit Namensräumen (Aliase usw.)

Eine Übersicht über die Verwendung finden Sie im Abschnitt "Verwendung grundlegender Komponenten" in der Dokumentation .

NikiC
quelle
2
Das ist fantastisch! Haben Sie einen Plan, um ihn aufrechtzuerhalten?
MikeSchinkel
1
@NikiC Danke Mann! Das ist eine großartige Bibliothek :-)
BVengerov
1
Wow, PHP 7.1-Unterstützung Anfang Dezember '11!
Dotancohen
9

Dies wird keine großartige Option für Sie sein, da es die reine PHP-Einschränkung verletzt, aber:

Vor einiger Zeit beschlossen die PHP-Interna-Leute, auf Lemon als Parsing-Technologie umzusteigen. Es gibt einen Zweig im PHP-SVN-Repo , der die erforderlichen Änderungen enthält.

Sie beschlossen, damit nicht fortzufahren , da sie feststellten, dass ihre Zitronenlösung etwa 10-15% langsamer ist. Aber die Niederlassung ist immer noch da.

Es gibt einen älteren Lemon-Parser , der als PHP-Erweiterung geschrieben wurde. Möglicherweise können Sie damit arbeiten. Es gibt auch dieses PEAR-Paket . Es gibt auch dieses andere Zitronenpaket (über diesen Blog-Beitrag über PGN ).

Selbst wenn Sie es zum Laufen bringen, bin ich mir natürlich nicht sicher, was Sie mit den Daten machen würden oder wie die Daten überhaupt aussehen.

Eine andere verrückte Option wäre ein Blick auf Quercus , eine PHP-Implementierung in Java. Sie müssten einen Parser geschrieben haben, vielleicht lohnt es sich, ihn zu untersuchen.

Charles
quelle
Zuallererst: +1 für umfangreiche Forschung. Das Hauptproblem ist nicht, dass es keine Möglichkeit gibt, einen Parser in PHP zu erstellen. Sie haben bereits erwähnt, dass Sie die Lemon PHP-Grammatik verwenden und kompilieren. Noch einfacher wäre es wahrscheinlich, die "echte" Yacc / Bison-Grammatik zu verwenden (auch dafür gibt es Compiler). Das Problem ist mehr, dass es wirklich sehr viel Arbeit ist, den yacc C-Code zum Generieren von Opcodes in yacc PHP-Code zum Generieren eines AST umzuwandeln. Also habe ich gesucht, ob jemand diese Arbeit bereits gemacht hat.
NikiC
@nikic Einer der Gründe, IMO, dass dies noch niemand getan hat, ist, dass es keine Spezifikation dafür gibt, was PHP wirklich ist und wie man es analysiert. PHP-Internals hat das gesamte Konzept bisher völlig abgelehnt. Daher gibt es außerhalb des PHP-Quellcodes selbst keine maßgebliche Quelle dafür, wie das Parsen tatsächlich durchgeführt werden kann. Ohne diese maßgebliche Bezugsquelle wird das Erstellen eines korrekten Parsers ein echtes Abenteuer. Dies bedeutet leider, dass das Beginnen mit den yacc- oder Lemon-Daten die beste Option sein kann.
Charles
@nikic, Charles: Es war ein echtes Abenteuer für unseren PHP-Parser. Ansatz: Lexer / Grammatik vorschlagen, Tausende von Dateien anprobieren, falsch liegen, anpassen, erneut versuchen. Es dauert ungefähr ein Jahr, bis ein robuster Parser für eine schlecht dokumentierte Sprache erstellt ist. Zumindest für uns. YMMV, aber wahrscheinlich nicht viel.
Ira Baxter
7

Das Metrik-Tool PHP Depend enthält Code zum Generieren eines AST aus einer vollständig in PHP geschriebenen PHP-Quelle. Für die Tokenisierung wird jedoch PHPs eigenes token_get_all verwendet.

Der Quellcode ist auf github verfügbar: https://github.com/manuelpichler/pdepend/tree/master/src/main/php/PHP/Depend

Die Implementierung des AST für einige Teile wie mathematische Ausdrücke war bei meiner letzten Überprüfung noch nicht abgeschlossen, aber laut dem Autor ist dies das Ziel.

Naderman
quelle
Hat ein AST, aber nicht für die "mathematischen Operationen" (ich nehme an, Sie meinen "Ausdrücke"? Das ist ein wesentlicher Teil der Sprache, insbesondere wenn Sie bedenken, dass doppelt zitierte "String-Literale" (mit eingebetteten Ausdrücken) wirklich nur komplex sind Zeichenfolge Ausdrücke.
Ira Baxter
2
Du hast das Kopfgeld bekommen, weil dies die naheliegendste Antwort auf die Frage ist. Aber offensichtlich ist es nicht wirklich verwendbar, weil es die Hälfte der PHP-Grammatik fehlt ...
NikiC
Der Inhalt dieses Beitrags ist veraltet. Seitdem wurde aktiv entwickelt, obwohl ich nicht weiß, wie gut es die PHP-Grammatik unterstützt.
nhahtdh
4

Nun, das ist nicht in PHP, sorry, aber das Erstellen dieser Art von Maschinen ist schwierig, und PHP ist nicht besonders für die Aufgabe der Sprachverarbeitung geeignet.

Unser PHP-Frontend bietet vollständiges Parsen von PHP 4.x und 5.x (EDIT 9/2016: behandelt jetzt PHP 7), erstellt automatisch ASTs mit allen Details einer vollständigen PHP-Grammatik und kann aus den ASTs kompilierbaren Quelltext generieren. Dies ist schwieriger, als es sich anhört, wenn Sie alle verrückten Details berücksichtigen, einschließlich seltsamer String-Literale, erfasster Kommentare, Zahlen mit Radix usw.

Aber ASTs sind kaum genug (Sie haben bereits beobachtet, dass Token nicht einmal genug sind).

Das DMS Software Reengineering Toolkit, auf dessen Grundlage es aufgebaut ist, bietet Unterstützung für Analysen und willkürliche Transformationen der ASTs. Es werden auch große Dateisätze gleichzeitig gelesen, was Analysen und Transformationen über PHP-Dateien hinweg ermöglicht.

Ira Baxter
quelle
1
Nur als Antwort auf den ersten Satz: Es gibt bereits Parser-Generatoren, die einen Parser aus einem Yacc-Grammatiker (z. B. kmyacc) generieren können. Das heißt, es gibt keinen großen Unterschied zwischen dem Erstellen in PHP und dem Erstellen in einer anderen Sprache. Alles was Sie tun müssen, ist "nur" (Ironie), den C-Code in der Datei zend_language_parser.y durch PHP-Code zu ersetzen, der einen Knotenbaum aufbaut.
NikiC
Und zum Rest: Ich hätte wirklich gerne eine PHP-Lösung. Aber wenn (und das scheint sehr wahrscheinlich) nichts dergleichen ist, werde ich wahrscheinlich etwas anderes verwenden. Ich habe hier auf SO schon mehrmals von DMS gehört, ich werde es mir ansehen.
NikiC
@ninkic: Alle Turing-Maschinen (einschließlich PHP) können alle anderen Turing-Maschinen simulieren. Ja, natürlich ist es möglich, sie in PHP zu erstellen. Aber a) es wird nur der Parser erstellt; Ich denke, der PHP-Parser ist nicht dafür ausgelegt, einen Baum zu erstellen, sondern den PHP-P-Code-Generator zu speisen, und ich denke, Sie werden feststellen, dass die Anforderungen unterschiedlich sind, und b) die Leute machen wiederholt den Fehler, dies anzunehmen der AST, alles andere ist einfach; Sie machen diesen Fehler größtenteils, weil sie keine Erfahrung mit komplexen Dingen mit ASTs haben. Ich habe DMS erstellt, weil diese Annahme falsch ist.
Ira Baxter
1
a) Ja, der PHP-Parser dient nicht zum Erstellen eines Analysebaums, sondern zum Erstellen eines Opcode-Streams. Aus diesem Grund ist es kaum möglich, den Zend-Sprachparser automatisch in PHP zu konvertieren. b) Ich bin wahrscheinlich einer von denen, die diesen Fehler machen;) Aufgrund der Tatsache, dass viele komplexe Manipulationen bereits mit dem reinen Token-Stream durchgeführt werden können, kam ich (in Ihren Augen fälschlicherweise?) zu dem Schluss, dass dies mit einem AST einfacher und einfacher wäre stabiler.
NikiC
@nikic: Die Lehren aus den 50 Jahren Compilertechnologie sind, dass jede Programmdarstellung bestimmte Dinge einfach macht. Sie können einige Programmmaninpulationen nur für den Text durchführen. Sie können mehr mit Token tun. Sie können noch mehr auf ASTs tun. Sie können wirklich interessante Dinge tun, wenn Sie über Symboltabellen, Steuerungs- und Datenflussinformationen (Diagramme) und variable Aliasing-Daten (Punkte-zu-Analyse) verfügen. Was Sie finden, wenn Sie versuchen, eine ausgefeilte Codegenerierung durchzuführen, ist, dass dies alles wirklich, wirklich nützliches Zeug ist.
Ira Baxter