Maison > développement back-end > tutoriel php > Comment PHP s'exécute - du code source au rendu

Comment PHP s'exécute - du code source au rendu

Jennifer Aniston
Libérer: 2025-02-10 10:11:11
original
785 Les gens l'ont consulté

Comment PHP s'exécute - du code source au rendu

Cet article a été revu par des pairs par Younes Rafie. Merci à tous les pairs examinateurs de SitePoint pour avoir fait du contenu SitePoint le meilleur possible!


Inspiré par un article récent sur la façon dont le code Ruby s'exécute, cet article couvre le processus d'exécution du code PHP.

Comment PHP s'exécute - du code source au rendu

Les plats clés

  • L'exécution du code PHP implique quatre étapes: lexing, l'analyse, la compilation et l'interprétation. Chaque étape est cruciale dans le processus de conversion du code source PHP en code lisible par machine.
  • lexing, ou tokenising, est le processus de transformation d'une chaîne (code source PHP) en une séquence de jetons. Chaque jeton est un identifiant nommé pour la valeur qu'il a égalée. Cette étape stocke également le lexème et le numéro de ligne du jeton correspondant.
  • L'étape d'analyse vérifie la validité de l'ordre du jeton et génère l'arbre de syntaxe abstrait (AST). L'AST est une vue d'arbre du code source utilisé pendant l'étape de compilation.
  • L'étape de compilation émet des opcodes en traversant l'AST et effectue des optimisations comme la résolution des appels de fonction avec des arguments littéraux et le pliage des expressions mathématiques constantes. La sortie de cette étape peut être inspectée à l'aide d'Opcache, de VLD et de phpdbg.
  • L'étape d'interprétation est la dernière étape où les opcodes sont exécutés sur la machine virtuelle Zend Engine (ZE). La sortie de cette étape est ce que votre script PHP sort via des commandes telles que Echo, Print, Var_dump, etc.

Introduction

Il se passe beaucoup de choses sous le capot lorsque nous exécutons un morceau de code PHP. D'une manière générale, l'interprète PHP passe par quatre étapes lors de l'exécution du code:

  1. lexing
  2. analyse
  3. Compilation
  4. Interprétation

Cet article parcourra ces étapes et montrera comment nous pouvons voir la sortie de chaque étape pour vraiment voir ce qui se passe. Notez que bien que certaines des extensions utilisées devraient déjà faire partie de votre installation PHP (comme le tokenizer et l'opcache), d'autres devront être installés et activées manuellement (comme PHP-AST et VLD).

Étape 1 - Lexing

lexing (ou tokenising) est le processus de transformation d'une chaîne (code source PHP, dans ce cas) en une séquence de jetons. Un jeton est simplement un identifiant nommé pour la valeur qu'il a égalée. PHP utilise RE2C pour générer son lexer à partir du fichier de définition zend_language_scanner.l.

Nous pouvons voir la sortie de l'étape de lexing via l'extension du tokenizer:

$code = <<<'code'
<span><span><?php
</span></span><span><span>$a = 1;
</span></span><span>code<span>;
</span></span><span>
</span><span><span>$tokens = token_get_all($code);
</span></span><span>
</span><span><span>foreach ($tokens as $token) {
</span></span><span>    <span>if (is_array($token)) {
</span></span><span>        <span>echo "Line <span><span>{$token[2]}</span>: "</span>, token_name($token[0]), " ('<span><span>{$token[1]}</span>')"</span>, PHP_EOL;
</span></span><span>    <span>} else {
</span></span><span>        <span>var_dump($token);
</span></span><span>    <span>}
</span></span><span><span>}
</span></span>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Sorties:

$code = <<<'code'
<span><span><?php
</span></span><span><span>$a = 1;
</span></span><span>code<span>;
</span></span><span>
</span><span><span>$tokens = token_get_all($code);
</span></span><span>
</span><span><span>foreach ($tokens as $token) {
</span></span><span>    <span>if (is_array($token)) {
</span></span><span>        <span>echo "Line <span><span>{$token[2]}</span>: "</span>, token_name($token[0]), " ('<span><span>{$token[1]}</span>')"</span>, PHP_EOL;
</span></span><span>    <span>} else {
</span></span><span>        <span>var_dump($token);
</span></span><span>    <span>}
</span></span><span><span>}
</span></span>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Il y a quelques points notables de la sortie ci-dessus. Le premier point est que toutes les pièces du code source ne sont pas nommées de jetons. Au lieu de cela, certains symboles sont considérés comme des jetons en eux-mêmes (tels que =, ;,:,?, Etc.). Le deuxième point est que le Lexer fait en fait un peu plus que simplement la sortie d'un flux de jetons. Il est également, dans la plupart des cas, stocke le lexème (la valeur correspondante par le jeton) et le numéro de ligne du jeton correspondant (qui est utilisé pour des choses comme les traces de pile).

Étape 2 - Parsing

L'analyseur est également généré, cette fois avec le bison via un fichier de grammaire BNF. PHP utilise une grammaire sans contexte LALR (1) (regardez vers l'avenir, gauche à droite). La partie à l'avance signifie simplement que l'analyseur est en mesure de regarder n jetons à venir (1, dans ce cas) pour résoudre les ambiguïtés qu'elle peut rencontrer pendant l'analyse. La partie de gauche à droite signifie qu'elle analyse le flux de jeton de gauche à droite.

L'étape d'analyse générée prend le flux de jetons du Lexer en entrée et a deux travaux. Il vérifie d'abord la validité de l'ordre des jetons en essayant de les faire correspondre à l'une des règles de grammaire définies dans son fichier de grammaire BNF. Cela garantit que des constructions de langage valides sont formées par les jetons dans le flux de jetons. Le deuxième travail de l'analyseur consiste à générer l'arbre de syntaxe abstrait (AST) - une vue d'arbre du code source qui sera utilisé au cours de la prochaine étape (compilation).

Nous pouvons afficher une forme de l'AST produit par l'analyseur en utilisant l'extension PHP-AST. L'AST interne n'est pas directement exposé car il n'est pas particulièrement «propre» pour fonctionner (en termes de cohérence et d'utilisation générale), et donc l'extension PHP-AST effectue quelques transformations sur elle pour rendre plus agréable à travailler.

Jetons un coup d'œil à l'AST pour un morceau de code rudimentaire:

Line 1: T_OPEN_TAG ('<?php
')
Line 2: T_VARIABLE ('$a')
Line 2: T_WHITESPACE (' ')
string(1) "="
Line 2: T_WHITESPACE (' ')
Line 2: T_LNUMBER ('1')
string(1) ";"
Copier après la connexion
Copier après la connexion

Sortie:

$code = <<<'code'
<span><span><?php
</span></span><span><span>$a = 1;
</span></span><span>code<span>;
</span></span><span>
</span><span><span>print_r(ast<span>\parse_code</span>($code, 30));
</span></span>
Copier après la connexion
Copier après la connexion

Les nœuds d'arborescence (qui sont généralement de type ASTNode) ont plusieurs propriétés:

  • KING - Une valeur entière pour représenter le type de nœud; Chacun a une constante correspondante (par exemple AST_STMT_LIST => 132, AST_ASSIGN => 517, AST_VAR => 256)
  • Flags - Un entier qui spécifie le comportement surchargé (par exemple, un nœud astast_binary_op aura des drapeaux pour différencier le fonctionnement binaire qui se produit)
  • Lineno - Le numéro de ligne, comme le montre les informations de jeton plus tôt
  • Enfants - Sub nœuds, généralement des parties du nœud décomposés (par exemple, un nœud de fonction aura les enfants: paramètres, type de retour, corps, etc.)

La sortie AST de cette étape est prête à travailler pour des outils tels que les analyseurs de code statique (par exemple Phan).

Étape 3 - Compilation

L'étape de compilation consomme l'AST, où il émet des opcodes en traversant récursivement l'arbre. Cette étape effectue également quelques optimisations. Il s'agit notamment de résoudre certains appels de fonction avec des arguments littéraux (tels que Strlen ("ABC") à int (3)) et le pliage des expressions mathématiques constantes (telles que 60 * 60 * 24 à int (86400)).

Nous pouvons inspecter la sortie OPCode à ce stade de plusieurs façons, y compris avec Opcache, VLD et PHPDBG. Je vais utiliser VLD pour cela, car je pense que la sortie est plus sympathique à regarder.

Voyons quelle est la sortie pour le script file.php suivant:

$code = <<<'code'
<span><span><?php
</span></span><span><span>$a = 1;
</span></span><span>code<span>;
</span></span><span>
</span><span><span>$tokens = token_get_all($code);
</span></span><span>
</span><span><span>foreach ($tokens as $token) {
</span></span><span>    <span>if (is_array($token)) {
</span></span><span>        <span>echo "Line <span><span>{$token[2]}</span>: "</span>, token_name($token[0]), " ('<span><span>{$token[1]}</span>')"</span>, PHP_EOL;
</span></span><span>    <span>} else {
</span></span><span>        <span>var_dump($token);
</span></span><span>    <span>}
</span></span><span><span>}
</span></span>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Exécution de la commande suivante:

Line 1: T_OPEN_TAG ('<?php
')
Line 2: T_VARIABLE ('$a')
Line 2: T_WHITESPACE (' ')
string(1) "="
Line 2: T_WHITESPACE (' ')
Line 2: T_LNUMBER ('1')
string(1) ";"
Copier après la connexion
Copier après la connexion

Notre sortie est:

$code = <<<'code'
<span><span><?php
</span></span><span><span>$a = 1;
</span></span><span>code<span>;
</span></span><span>
</span><span><span>print_r(ast<span>\parse_code</span>($code, 30));
</span></span>
Copier après la connexion
Copier après la connexion

Les OPCodes ressemblent au code source d'origine, suffisamment pour suivre les opérations de base. (Je ne vais pas plonger dans les détails d'Opcodes dans cet article, car cela prendrait plusieurs articles entiers en soi.) en a fait en résolvant la condition constante (php_version === '7.1.0-dev') à true.

OPCACHE fait plus que la simple mise en cache OPCodes (en contournant ainsi les étapes de lexing, d'analyse et de compilation). Il regorge également de nombreux niveaux d'optimisations différents. Passons au niveau d'optimisation à quatre passes pour voir ce qui sort:

Commande:

ast\Node Object (
    [kind] => 132
    [flags] => 0
    [lineno] => 1
    [children] => Array (
        [0] => ast\Node Object (
            [kind] => 517
            [flags] => 0
            [lineno] => 2
            [children] => Array (
                [var] => ast\Node Object (
                    [kind] => 256
                    [flags] => 0
                    [lineno] => 2
                    [children] => Array (
                        [name] => a
                    )
                )
                [expr] => 1
            )
        )
    )
)
Copier après la connexion

Sortie:

<span>if (PHP_VERSION === '7.1.0-dev') {
</span>    <span>echo 'Yay', PHP_EOL;
</span><span>}
</span>
Copier après la connexion

Nous pouvons voir que la condition constante a été supprimée et que les deux instructions d'écho ont été compactées en une seule instruction. Ce ne sont qu'un avant-goût des nombreuses optimisations que l'opcache s'applique lors de l'exécution de passes sur les opcodes d'un script. Je ne passerai pas par les différents niveaux d'optimisation dans cet article, car ce serait également un article en soi.

Étape 4 - Interprétation

L'étape finale est l'interprétation des opcodes. C'est là que les opcodes sont exécutés sur la machine virtuelle Zend Engine (ZE). Il y a en fait très peu de choses à dire sur cette étape (d'un point de vue de haut niveau, au moins). La sortie est à peu près tout ce que votre script PHP sort via des commandes telles que Echo, Print, Var_dump, etc.

Donc, au lieu de creuser dans quelque chose de complexe à ce stade, voici un fait amusant: PHP se demande comme une dépendance lors de la génération de sa propre machine virtuelle. En effet

Conclusion

Nous avons jeté un bref aperçu des quatre étapes que l'interprète PHP passe lors de l'exécution du code PHP. Cela a impliqué l'utilisation de diverses extensions (y compris le tokenizer, le php-ast, l'opcache et le VLD) pour manipuler et afficher la sortie de chaque étape.

J'espère que cet article a contribué à vous fournir une meilleure compréhension holistique de l'interprète de PHP, ainsi que l'importance de l'extension Opcache (pour ses capacités de mise en cache et d'optimisation).

Questions fréquemment posées (FAQ) sur le processus d'exécution PHP

Quel est le rôle de l'interprète PHP dans le processus d'exécution?

L'interprète PHP joue un rôle crucial dans le processus d'exécution PHP. Il est responsable de la conversion du code source PHP en code lisible par machine. L'interprète lit la ligne de script PHP ligne par ligne, interprète chaque ligne et effectue les opérations nécessaires. Il est également responsable de la gestion des erreurs et des exceptions pendant le processus d'exécution. L'interprète PHP est un composant clé de l'environnement d'exécution PHP, qui comprend également le serveur Web et les extensions PHP.

Comment fonctionne le moteur PHP?

Le moteur PHP est le cœur de le processus d'exécution PHP. Il est responsable de l'analyse du script PHP, de la compilation en bytecode, puis de l'exécution du bytecode. Le moteur PHP utilise un processus en deux étapes pour exécuter des scripts PHP. Tout d'abord, il analyse le script PHP et le convertit en une arborescence de syntaxe abstraite (AST). Ensuite, il compile l'AST en bytecode et l'exécute. Le moteur PHP comprend également un gestionnaire de mémoire et un collecteur de déchets pour gérer l'utilisation de la mémoire pendant le processus d'exécution.

Quelle est la différence entre l'interface de ligne de commande de PHP et l'interface du serveur Web?

La commande PHP de PHP - Interface de ligne (CLI) et l'interface du serveur Web sont deux façons différentes d'exécuter des scripts PHP. La CLI est utilisée pour exécuter des scripts PHP à partir de la ligne de commande, tandis que l'interface du serveur Web est utilisée pour exécuter des scripts PHP en réponse aux demandes Web. La principale différence entre les deux interfaces est la façon dont ils gèrent l'entrée et la sortie. Dans la CLI, l'entrée est lue à partir de la ligne de commande et la sortie est écrite sur la console. Dans l'interface du serveur Web, l'entrée est lue à partir de la demande HTTP et la sortie est écrite dans la réponse HTTP.

Comment PHP gère-t-il les erreurs pendant le processus d'exécution?

PHP a une gestion des erreurs robuste mécanisme qui lui permet de gérer les erreurs pendant le processus d'exécution. Lorsqu'une erreur se produit, PHP génère un message d'erreur et l'envoie au gestionnaire d'erreur. Le gestionnaire d'erreur peut afficher le message d'erreur, le enregistrer ou l'ignorer, en fonction des paramètres de rapport d'erreur. PHP prend également en charge la manipulation des exceptions, ce qui lui permet de gérer les erreurs de manière plus structurée et gérable.

Quel est le rôle des extensions de PHP dans le processus d'exécution?

Les extensions PHP sont des modules qui ajoutent de nouvelles fonctionnalités et fonctionnalités au langage PHP. Ils sont chargés dans l'environnement d'exécution PHP pendant le processus d'exécution et peuvent être utilisés pour effectuer une large gamme de tâches, de l'accès à la base de données au traitement d'image. Les extensions de PHP sont écrites en C et sont compilées en code machine, ce qui les rend très rapides et efficaces. Ils sont un composant clé de l'écosystème PHP et contribuent à sa flexibilité et à sa puissance.

Comment PHP optimise-t-il le processus d'exécution?

PHP utilise plusieurs techniques pour optimiser le processus d'exécution. L'une de ces techniques est la mise en cache Opcode, qui implique le stockage du bytecode généré par le moteur PHP en mémoire afin qu'il puisse être réutilisé dans les exécutions suivantes. Cela élimine la nécessité d'analyser et de compiler le script PHP à chaque fois qu'il est exécuté, ce qui entraîne des améliorations de performances significatives. PHP utilise également la compilation JIT-Time (JIT), qui consiste à compiler des bytecodes dans le code machine à l'exécution pour améliorer davantage les performances.

Comment PHP gère-t-il la gestion de la mémoire pendant le processus d'exécution?

PHP possède un gestionnaire de mémoire intégré qui gère l'allocation de mémoire et la transmission pendant le processus d'exécution. Le gestionnaire de mémoire alloue la mémoire pour les variables et les structures de données selon les besoins, et traite la mémoire lorsqu'elle n'est plus nécessaire. PHP a également un collecteur de déchets qui libère automatiquement de la mémoire qui n'est plus utilisée. Cela aide à prévenir les fuites de mémoire et à maintenir l'utilisation de la mémoire sous contrôle.

Quel est le rôle du serveur Web dans le processus d'exécution PHP?

Le serveur Web joue un rôle clé dans l'exécution PHP processus. Il est responsable de la gestion des demandes HTTP, de l'exécution de scripts PHP en réponse à ces demandes et de renvoyer des réponses HTTP au client. Le serveur Web travaille en étroite collaboration avec l'interprète PHP et le moteur PHP pour exécuter des scripts PHP et générer des pages Web dynamiques. Les serveurs Web les plus couramment utilisés pour PHP sont Apache et Nginx.

Comment PHP gère-t-il les interactions de la base de données pendant le processus d'exécution?

PHP a une prise en charge intégrée pour une large gamme de bases de données, y compris MySQL, PostgreSQL et SQLite. Il utilise des extensions spécifiques à la base de données pour interagir avec ces bases de données pendant le processus d'exécution. Ces extensions fournissent un ensemble de fonctions qui peuvent être utilisées pour se connecter à la base de données, exécuter les requêtes SQL, récupérer les résultats et gérer les erreurs. PHP prend également en charge l'extension PDO (PHP Data Objectts), qui fournit une interface de base de données-indésirable pour les interactions de base de données.

Comment PHP gère la gestion des sessions pendant le processus d'exécution?

PHP a une prise en charge intégrée pour la gestion de session, ce qui lui permet de maintenir l'état entre les différentes demandes HTTP. Lorsqu'une session est démarrée, PHP crée un identifiant de session unique et le stocke dans un cookie sur le navigateur du client. Cet ID de session est ensuite renvoyé au serveur avec chaque demande suivante, permettant à PHP d'identifier le client et de récupérer les données de session correspondantes. Les fonctionnalités de gestion de session de PHP facilitent la mise en œuvre de l'authentification des utilisateurs, des paniers d'achat et d'autres fonctionnalités d'état dans les applications Web.

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!

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
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal