Quelques introductions à l'Arbre de Syntaxe Abstraite (AST) dans les nouvelles fonctionnalités de PHP7

不言
Libérer: 2023-04-03 10:22:02
original
2205 Les gens l'ont consulté

Cet article partage avec vous une introduction à l'arbre de syntaxe abstraite (AST) dans les nouvelles fonctionnalités de PHP7. Le contenu est très bon. Les amis dans le besoin peuvent s'y référer.

Cet article analyse les changements apportés par la nouvelle fonctionnalité de PHP7, Abstract Syntax Tree (AST). Partagez-le avec tout le monde pour votre référence. Les détails sont les suivants :

La plupart du contenu ici est basé sur le document RFC de l'AST : https://wiki.php.net/rfc/abstractsyntaxtree. de compréhension, il est extrait de la section du document source est introduite.

Cet article ne vous dira pas ce qu'est un arbre de syntaxe abstraite. Vous devez le comprendre vous-même. Cet article décrit uniquement certains changements qu'AST apporte à PHP.

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. Analyse : analyse syntaxique, génération de tableaux d'opérations à 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. Lexing : analyse lexicale, conversion des fichiers sources en flux de jetons ;

  2. Parsing : analyse syntaxique, génération d'arbres de syntaxe abstraits à partir de flux de jetons

  3. Compilation : Générez des tableaux d'opérations à partir d'arbres de syntaxe abstraits.

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) :


php-ng php-ast diff
SMALL 0.180s 0.160s -12.5%
MEDIUM 1.492s 1.268s -17.7%
LARGE 6.703s 5.736s -16.9%

Pic de mémoire dans une seule compilation :


php-ng php-ast diff
SMALL 378kB 414kB +9.5%
MEDIUM 507kB 643kB +26.8%
LARGE 1084kB 1857kB +71.3%

Les résultats des tests d'une seule compilation peuvent ne pas représenter l'utilisation réelle. Voici les résultats d'un test de projet complet utilisant PhpParser :


php-ng php-ast diff
TIME 25.5ms 22.8ms -11.8%
MEMORY 2360kB 2482kB +5.1%

Les tests montrent qu'après l'utilisation d'AST, le temps d'exécution global du programme est amélioré d'environ 10 à 15 %, mais la consommation de mémoire augmente également. L'augmentation est évidente dans une seule compilation de fichiers volumineux, mais pas dans la. tout le processus d’exécution du projet. Problème très grave.

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 yield dans un contexte d'expression (comme sur le côté droit d'une expression d'affectation), vous devez placer yield Utilisez des parenthèses des deux côtés de la déclaration :

<?php
$result = yield fn(); // 不合法的
$result = (yield fn()); // 合法的
Copier après la connexion

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;
Copier après la connexion

Bien sûr, vous devez suivre les scénarios d'application de yield.

Les crochets n'affectent pas le comportement

En PHP5, les significations de ($foo)[&#39;bar&#39;] = &#39;baz&#39; et $foo[&#39;bar&#39;] = &#39;baz&#39; sont différentes. En fait, l'ancienne façon d'écrire est illégale, et vous obtiendrez l'erreur suivante :

<?php
($foo)[&#39;bar&#39;] = &#39;baz&#39;;
# PHP Parse error: Syntax error, unexpected &#39;[&#39; on line 1
Copier après la connexion

Mais en PHP7, les deux façons d'écrire 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()));
Copier après la connexion

Le code ci-dessus ne le sera pas. alert en PHP5 à moins d'utiliser byRef(func()) pour appeler, mais en PHP7, qu'il y ait ou non des parenthèses des deux côtés de func(), l'erreur suivante se produira :

Normes strictes PHP : seules les variables doivent être transmises par référence ...

List() change

Le comportement du mot-clé list a beaucoup changé. L'ordre dans lequel la liste attribue des valeurs aux variables (l'ordre autour du signe égal en même temps) était autrefois de droite à gauche, mais est maintenant de gauche à droite :

<?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 是没有疑问的。
Copier après la connexion

La raison car le changement ci-dessus est précisément dû au processus d'affectation dans PHP5 Dans , 3 sera rempli en premier dans le tableau et 1 en dernier, mais maintenant l'ordre a changé.

Les mêmes changements sont :

<?php
$a = [1, 2];
list($a, $b) = $a;
// PHP5: $a = 1, $b = 2
// PHP7: $a = 1, $b = null + "Undefined index 1"
Copier après la connexion

Cela est dû au fait que dans le processus d'affectation précédent, $b a d'abord obtenu 2, puis la valeur de $a est devenue 1, mais maintenant $a devient 1 en premier, et n'est plus un tableau, donc $b devient nul.

La liste n'est désormais accessible qu'une seule fois par offset :

<?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];
Copier après la connexion

Les membres de liste vides sont désormais totalement interdits, auparavant seulement dans certains cas :

<?php
list() = $a;   // 不合法
list($b, list()) = $a; // 不合法
foreach ($a as list()) // 不合法 (PHP5 中也不合法)
Copier après la connexion

L'ordre de affectation de référence

L'ordre d'affectation de référence est de droite à gauche en PHP5, et maintenant il est de gauche à droite :

<?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)
}
Copier après la connexion

__la méthode clone peut être appelée directement

peut désormais utiliser directement la méthode d'écriture $obj->__clone() pour appeler la méthode __clone. __clone est la seule méthode magique dont il était auparavant interdit d'être appelée directement. Auparavant, vous obteniez une erreur comme celle-ci :

Erreur fatale : impossible d'appeler la méthode __clone() sur les objets - utilisez 'clone $obj'. à la place dans ...

Cohérence de la syntaxe variable

AST résout également certains problèmes de cohérence de la syntaxe qui ont été soulevés dans une autre RFC : https://wiki.php net/rfc/uniform_variable_syntax.

Dans la nouvelle implémentation, la signification de certaines expressions grammaticales précédentes est quelque peu différente de celle d'aujourd'hui. Pour plus de détails, veuillez vous référer au tableau suivant :

Expression PHP5 PHP7
$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']
$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']
$foo->$bar['baz']() $foo->{$bar['baz']}() ($foo->$bar)['baz']()
Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()
Dans l'ensemble, c'est toujours la même chose. l'ordre était de droite à gauche, maintenant il est de gauche à droite, tout en suivant le principe selon lequel les parenthèses n'affectent pas le comportement. Ces méthodes complexes d’écriture de variables doivent être prises en compte dans le développement réel.

Recommandations associées :

Cinq façons de vous apprendre à désactiver les informations d'écho d'erreur php

Protocole FastCGI en php Analyse du code source de

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!