Was ist ein abstrakter Syntaxbaum?
Der abstrakte Syntaxbaum (AST) ist eine Baumdarstellung der abstrakten Syntaxstruktur des Quellcodes. Jeder Knoten im Baum stellt eine Struktur im Quellcode dar. Aufgrund der abstrakten Syntax ist er abstrakt Der Baum repräsentiert nicht jedes Detail der echten Grammatik. Beispielsweise sind verschachtelte Klammern in der Struktur des Baums implizit und werden nicht in Form von Knoten dargestellt. Der abstrakte Syntaxbaum hängt nicht von der Grammatik der Quellsprache ab, was bedeutet, dass die in der Syntaxanalysephase verwendete kontextfreie Grammatik [Grammatik sind die formalen Regeln, die zur Beschreibung der grammatikalischen Struktur einer Sprache verwendet werden. Jede Sprache hat ihre eigene Grammatik, egal ob es sich um Maschinensprache oder natürliche Sprache handelt. 】, da beim Schreiben von Grammatik häufig äquivalente Transformationen an der Grammatik durchgeführt werden (Beseitigung der Linksrekursion, Backtracking, Mehrdeutigkeit usw.), die einige redundante Komponenten in die Grammatikanalyse einführen, sich negativ auf die nachfolgenden Phasen auswirken und sogar machen ganze Bühne verwirrend. Aus diesem Grund müssen viele Compiler häufig unabhängig voneinander Syntaxanalysebäume erstellen, um eine klare Schnittstelle für das Front-End und das Back-End einzurichten
Die Projekthomepage von PHP-Parser ist https://github.com/nikic/ PHP-Parser. Es kann mehrere PHP-Versionen perfekt analysieren und einen abstrakten Syntaxbaum generieren.
Neuer Ausführungsprozess
Eine wichtige Änderung im Kern von PHP7 ist die Hinzufügung von AST. In PHP5 ist der Ausführungsprozess von PHP-Skripten zu Opcodes:
1.Lexing: lexikalische Scan-Analyse, Konvertieren von Quelldateien in Token-Streams;
2.Parsing: Syntaxanalyse, Op-Arrays sind in dieser Phase generiert.
In PHP7 werden Op-Arrays nicht mehr direkt während der Syntaxanalysephase generiert, sondern AST wird zuerst generiert, daher gibt es einen weiteren Schritt im Prozess:
1. Lexing: Lexikalisches Scannen Analyse, Konvertieren der Quelldatei in einen Token-Stream;
2.Parsing: Syntaxanalyse, Generieren eines abstrakten Syntaxbaums aus dem Token-Stream
3.Kompilierung: Generieren von Op-Arrays aus dem abstrakten Syntaxbaum.
Ausführungszeit und Speicherverbrauch
Von den oben genannten Schritten ist dies ein Schritt mehr als der vorherige Prozess, sodass dies nach gesundem Menschenverstand die Programmausführung erhöht Zeit- und Speicherverbrauch. Tatsächlich hat sich jedoch die Speichernutzung erhöht, die Ausführungszeit jedoch abgenommen.
Die folgenden Ergebnisse werden durch das Testen von drei Skripten erzielt: klein (ca. 100 Zeilen Code), mittel (ca. 700 Zeilen) und groß (ca. 2800 Zeilen). Testskript: https://gist.github .com/nikic/289b0c7538b46c2220bc.
Ausführungszeit für das 100-fache Kompilieren jeder Datei (beachten Sie, dass das Testergebnis des Artikels 14 Jahre alt ist, als PHP7 noch PHP-NG hieß):
Speicherspitze in einer einzelnen Zusammenstellung:
Die Testergebnisse einer einzelnen Zusammenstellung spiegeln möglicherweise nicht die tatsächliche Nutzung wider. Im Folgenden wird PhpParser verwendet Die Ergebnisse des vollständigen Projekttests:
Der Test zeigt, dass sich nach der Verwendung von AST die Gesamtausführungszeit des Programms um etwa 10 bis 15 % verbessert, aber die Der Speicherverbrauch ist ebenfalls erhöht. Der Anstieg ist bei einer einzelnen Zusammenstellung großer Dateien offensichtlich, stellt jedoch während der gesamten Projektausführung kein ernstes Problem dar.
Beachten Sie außerdem, dass die oben genannten Ergebnisse alle ohne Opcache gelten. Wenn Opcache in einer Produktionsumgebung aktiviert ist, stellt der Anstieg des Speicherverbrauchs kein großes Problem dar.
Semantische Änderungen
Wenn es sich nur um eine Zeitoptimierung handelt, scheint dies kein ausreichender Grund für die Verwendung von AST zu sein. Tatsächlich basiert die Implementierung von AST nicht auf Überlegungen zur Zeitoptimierung, sondern auf der Lösung von Syntaxproblemen. Werfen wir einen Blick auf einige Änderungen in der Semantik.
Yield erfordert keine Klammern
Wenn Sie Yield in der PHP5-Implementierung in einem Ausdruckskontext verwenden (z. B. auf der rechten Seite eines Zuweisungsausdrucks), werden Sie Sie müssen auf beiden Seiten der Yield-Deklaration Klammern verwenden:
<?php $result = yield fn(); // 不合法的 $result = (yield fn()); // 合法的
Dieses Verhalten ist nur auf die Implementierungsbeschränkungen von PHP5 zurückzuführen. In PHP7 sind Klammern nicht mehr erforderlich. Folgende Schreibmethoden sind also ebenfalls zulässig:
<?php $result = yield; $result = yield $v; $result = yield $k => $v;
Natürlich müssen Sie sich dabei an die Anwendungsszenarien von yield halten.
Klammern haben keinen Einfluss auf das Verhalten
In PHP5
<?php ($foo)['bar'] = 'baz'; # PHP Parse error: Syntax error, unexpected '[' on line 1
Aber in PHP7 bedeuten die beiden Schreibweisen dasselbe.
Wenn die Parameter der Funktion in Klammern stehen, gibt es ebenfalls ein Problem mit der Typprüfung. Dieses Problem wurde auch in PHP7 gelöst:
<?php function func() { return []; } function byRef(array &$a) { } byRef((func()));
Der obige Code wird nicht angezeigt PHP5, es sei denn, byRef wird verwendet (func()), aber in PHP7 tritt der folgende Fehler auf, unabhängig davon, ob auf beiden Seiten von func() Klammern vorhanden sind:
PHP Strict standards: Only variables should be passed by reference ...
Änderungen in list()
list 关键字的行为改变了很多。list 给变量赋值的顺序(等号左右同时的顺序)以前是从右至左,现在是从左到右:
<?php list($array[], $array[], $array[]) = [1, 2, 3]; var_dump($array); // PHP5: $array = [3, 2, 1] // PHP7: $array = [1, 2, 3] # 注意这里的左右的顺序指的是等号左右同时的顺序, # list($a, $b) = [1, 2] 这种使用中 $a == 1, $b == 2 是没有疑问的。
产生上面变化的原因正是因为在 PHP5 的赋值过程中,3 会最先被填入数组,1 最后,但是现在顺序改变了。
同样的变化还有:
<?php $a = [1, 2]; list($a, $b) = $a; // PHP5: $a = 1, $b = 2 // PHP7: $a = 1, $b = null + "Undefined index 1"
这是因为在以前的赋值过程中 $b 先得到 2,然后 $a 的值才变成1,但是现在 $a 先变成了 1,不再是数组,所以 $b 就成了null。
list 现在只会访问每个偏移量一次
<?php list(list($a, $b)) = $array; // PHP5: $b = $array[0][1]; $a = $array[0][0]; // PHP7: // 会产生一个中间变量,得到 $array[0] 的值 $_tmp = $array[0]; $a = $_tmp[0]; $b = $_tmp[1];
空的 list 成员现在是全部禁止的,以前只是在某些情况下:
<?php list() = $a; // 不合法 list($b, list()) = $a; // 不合法 foreach ($a as list()) // 不合法 (PHP5 中也不合法)
引用赋值的顺序
引用赋值的顺序在 PHP5 中是从右到左的,现在时从左到右:
<?php $obj = new stdClass; $obj->a = &$obj->b; $obj->b = 1; var_dump($obj); // PHP5: object(stdClass)#1 (2) { ["b"] => &int(1) ["a"] => &int(1) } // PHP7: object(stdClass)#1 (2) { ["a"] => &int(1) ["b"] => &int(1) }
__clone 方法可以直接调用
现在可以直接使用 $obj->__clone() 的写法去调用 __clone 方法。 __clone 是之前唯一一个被禁止直接调用的魔术方法,之前你会得到一个这样的错误:
Fatal error:Cannot call __clone() method on objects -use 'clone $obj' instead in...
变量语法一致性
AST 也解决了一些语法一致性的问题,这些问题是在另外一个 RFC 中被提出的:https://wiki.php.net/rfc/uniform_variable_syntax.
在新的实现上,以前的一些语法表达的含义和现在有些不同,具体的可以参照下面的表格:
整体上还是以前的顺序是从右到左,现在从左到右,同时也遵循括号不影响行为的原则。这些复杂的变量写法是在实际开发中需要注意的。
相关推荐:《PHP教程》
Das obige ist der detaillierte Inhalt vonÄnderungen durch den Abstract Syntax Tree (AST) von PHP7. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!