Qu'est-ce qu'un arbre syntaxique abstrait ?
L'arbre de syntaxe abstraite (AST) est une représentation arborescente de la structure syntaxique abstraite du code source. Chaque nœud de l'arborescence représente une structure dans le code source, il est donc abstrait car la syntaxe abstraite. L'arbre ne représente pas tous les détails de la grammaire réelle. Par exemple, les crochets imbriqués sont implicites dans la structure de l'arbre et ne sont pas présentés sous forme de nœuds. L'arbre syntaxique abstrait ne dépend pas de la grammaire de la langue source, ce qui signifie que la grammaire hors contexte utilisée dans l'étape d'analyse syntaxique [La grammaire est les règles formelles utilisées pour décrire la structure grammaticale d'une langue. Chaque langage a sa propre grammaire, qu’il s’agisse du langage machine ou du langage naturel. 】, car lors de l'écriture de la grammaire, des transformations équivalentes sont souvent effectuées sur la grammaire (élimination de la récursion à gauche, retour en arrière, ambiguïté, etc.), ce qui introduira des composants redondants dans l'analyse grammaticale, affectera négativement les étapes suivantes, et même rendra le toute la scène est déroutante. Pour cette raison, de nombreux compilateurs doivent souvent construire des arbres d'analyse syntaxique indépendamment afin d'établir une interface claire pour le front-end et le back-end
La page d'accueil du projet PHP-Parser est https://github.com/nikic/ PHP-Parseur. Il peut parfaitement analyser plusieurs versions de PHP et générer un arbre de syntaxe abstrait.
Nouveau processus d'exécution
Un changement important dans le cœur de PHP7 est l'ajout d'AST. En PHP5, le processus d'exécution des scripts php en opcodes est :
1.Lexing : analyse lexicale, conversion des fichiers sources en flux de jetons
2.Parsing : analyse syntaxique, les tableaux d'opérations sont ; généré à ce stade.
En PHP7, les tableaux op ne sont plus directement générés lors de la phase d'analyse syntaxique, mais AST est généré en premier, il y a donc une étape supplémentaire dans le processus :
1. analyse, conversion du fichier source en flux de jetons ;
2.Parsing : analyse syntaxique, génération d'un arbre de syntaxe abstrait à partir du flux de jetons
3.Compilation : génération de tableaux d'opérations à partir d'un arbre de syntaxe abstrait ;
Temps d'exécution et consommation de mémoire
D'après les étapes ci-dessus, il s'agit d'une étape de plus que le processus précédent, donc selon le bon sens, cela augmentera l'exécution du programme utilisation du temps et de la mémoire. Mais en fait, l'utilisation de la mémoire a effectivement augmenté, mais le temps d'exécution a diminué.
Les résultats suivants sont obtenus en testant trois scripts : petit (environ 100 lignes de code), moyen (environ 700 lignes) et grand (environ 2800 lignes) Script de test : https://gist.github). .com/nikic/289b0c7538b46c2220bc.
Temps d'exécution de la compilation de chaque fichier 100 fois (à noter que le résultat du test de l'article date d'il y a 14 ans, lorsque PHP7 s'appelait encore PHP-NG) :
Pic de mémoire dans une seule compilation :
Les résultats des tests d'une seule compilation peuvent ne pas représenter l'utilisation réelle de PhpParser. Les résultats du test complet du projet :
Le test montre qu'après avoir utilisé AST, le temps d'exécution global du programme est amélioré d'environ 10% à 15%, mais le la consommation de mémoire est également augmentée, l'augmentation est évidente dans une seule compilation de fichiers volumineux, mais ce n'est pas un problème sérieux pendant toute l'exécution du projet.
Notez également que les résultats ci-dessus sont tous sans Opcache. Lorsque Opcache est activé dans un environnement de production, l'augmentation de la consommation de mémoire n'est pas un gros problème.
Changements sémantiques
S'il ne s'agit que d'une optimisation temporelle, cela ne semble pas être une raison suffisante pour utiliser AST. En fait, la mise en œuvre d’AST ne repose pas sur des considérations d’optimisation du temps, mais sur la résolution de problèmes de syntaxe. Jetons un coup d'œil à quelques changements de sémantique.
yield ne nécessite pas de parenthèses
Dans l'implémentation PHP5, si vous utilisez rendement dans un contexte d'expression (comme sur le côté droit d'une expression d'affectation), vous Vous devez utiliser des parenthèses des deux côtés de la déclaration de rendement :
<?php $result = yield fn(); // 不合法的 $result = (yield fn()); // 合法的
Ce comportement est uniquement dû aux limitations d'implémentation de PHP5. En PHP7, les parenthèses ne sont plus nécessaires. Par conséquent, les méthodes d'écriture suivantes sont également légales :
<?php $result = yield; $result = yield $v; $result = yield $k => $v;
Bien sûr, vous devez suivre les scénarios d'application du rendement.
Les crochets n'affectent pas le comportement
En PHP5,
<?php ($foo)['bar'] = 'baz'; # PHP Parse error: Syntax error, unexpected '[' on line 1
Mais en PHP7, les deux méthodes d'écriture signifient la même chose.
De même, si les paramètres de la fonction sont mis entre parenthèses, il y a un problème avec la vérification de type. Ce problème a également été résolu en PHP7 :
<?php function func() { return []; } function byRef(array &$a) { } byRef((func()));
Le code ci-dessus ne le sera pas. alert en PHP5 à moins d'utiliser byRef(func()) pour appeler, mais en PHP7, l'erreur suivante se produira, qu'il y ait ou non des parenthèses des deux côtés de func() :
PHP Strict standards: Only variables should be passed by reference ...
Modifications dans la liste()
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教程》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!