Fonctionnement du moteur Zend
Suivez PHP du code source aux opcodes, puis jusqu’à l’exécution.
Fonctionnement du moteur Zend est une leçon PHP Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage PHP Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours PHP Academy comprend 4 leçons au total.
À l'intérieur du moteur
PHP n'est pas interprété ligne par ligne à partir du code source. Le moteur Zend compile votre script en une représentation intermédiaire appelée codes opérationnels, puis une machine virtuelle les exécute. Comprendre cette chaîne de traitement permet de mieux comprendre les performances, OPcache et le JIT.
Cette leçon suit le parcours code source → jetons → AST → codes opérationnels → exécution par la VM.
La chaîne de traitement
Chaque requête adressée à un fichier PHP passe par quatre phases :
- Analyse lexicale — texte source → jetons (analyseur fondé sur re2c)
- Analyse syntaxique — jetons → arbre syntaxique abstrait (grammaire Bison)
- Compilation — AST → tableau de codes opérationnels (op_array)
- Exécution — la VM Zend parcourt les codes opérationnels
Sans OPcache, les trois premières phases se répètent à chaque requête.
Création des jetons
L'analyseur lexical transforme les caractères en jetons tels que T_VARIABLE, T_ECHO et T_STRING. PHP expose cette étape via token_get_all() / PhpToken, ce qui est exactement utilisé par des outils comme PHP-CS-Fixer.
<?php
$src = '<?php $x = 1 + 2; echo $x;';
foreach (PhpToken::tokenize($src) as $tok) {
if ($tok->isIgnorable()) continue; // skip whitespace
printf("%-12s %s\n", $tok->getTokenName(), trim($tok->text));
}
?>L'AST
Les jetons sont analysés pour former un arbre de nœuds — un nœud d'affectation dont les enfants sont une variable et une expression d'opération binaire. PHP construit cet AST en interne, tandis que nikic/php-parser en reconstruit un équivalent dans l'espace utilisateur pour des outils d'analyse statique comme PHPStan.
<?php
// Conceptual AST for: $x = 1 + 2;
//
// AST_ASSIGN
// ├── AST_VAR ($x)
// └── AST_BINARY_OP (+)
// ├── 1
// └── 2
//
// At compile time PHP folds 1 + 2 into a literal 3
// (constant folding) before generating opcodes.
echo "AST drives opcode generation\n";
?>Codes opérationnels
Le compilateur produit un tableau de codes opérationnels : une liste plate de codes opérationnels. Chaque code opérationnel possède un numéro (par exemple ZEND_ADD, ZEND_ECHO et ZEND_ASSIGN) et jusqu'à deux opérandes ainsi qu'un résultat, chacun étant une variable compilée (CV), une valeur temporaire (TMP) ou une constante.
<?php
// Opcodes for: $x = 1 + 2; echo $x;
//
// line op operands result
// --- ------------ ----------------- -------
// 1 ADD 1, 2 ~0
// 1 ASSIGN $x, ~0
// 1 ECHO $x
// 1 RETURN 1
//
// ~0 is a temporary; $x is a compiled variable (CV).
echo "op_array is what OPcache stores\n";
?>Inspecter les codes opérationnels
Vous pouvez afficher les codes opérationnels générés avec l'extension VLD ou avec opcache.opt_debug_level d'OPcache. Cela révèle l'évaluation des constantes, l'élimination du code mort et la façon dont le flux de contrôle devient une suite de codes opérationnels JMP/JMPZ.
# Dump opcodes with VLD
php -d vld.active=1 -d vld.execute=0 script.php
# Or via OPcache optimizer debug (pre/post optimization)
php -d opcache.opt_debug_level=0x10000 script.php # before opt
php -d opcache.opt_debug_level=0x20000 script.php # after optVariables compilées (CV)
Dans le code compilé, les variables locales ne sont pas recherchées dans une table de hachage : le compilateur attribue à chacune un emplacement CV numéroté. Accéder une deuxième fois à $x revient à utiliser un index de tableau, et non à rechercher un symbole dans la table des symboles. C'est une raison majeure de la rapidité des variables locales.
<?php
// Each named local gets a fixed CV slot at compile time:
// $a -> CV0 $b -> CV1 $sum -> CV2
function add(int $a, int $b): int {
$sum = $a + $b; // ADD CV0, CV1 -> CV2
return $sum; // RETURN CV2
}
echo add(2, 3) . PHP_EOL;
?>La boucle d'exécution de la VM
L'exécuteur (execute_ex) parcourt le tableau de codes opérationnels. Chaque code opérationnel correspond à une fonction gestionnaire ; PHP peut organiser cette distribution avec une immense instruction de sélection, des sauts calculés ou une combinaison des deux (le mode par défaut, le plus rapide avec les compilateurs compatibles). Le pointeur opline avance ; les codes opérationnels JMP le déplacent pour gérer le flux de contrôle.
<?php
// if ($n > 0) echo 'pos'; compiles roughly to:
//
// IS_SMALLER 0, $n -> ~T
// JMPZ ~T, ->L1 ; if false, skip
// ECHO 'pos'
// L1:
// RETURN 1
//
// The VM follows opline; JMPZ rewrites it conditionally.
$n = 5;
if ($n > 0) echo "pos\n";
?>Où intervient OPcache
OPcache met en cache le tableau de codes opérationnels en mémoire partagée, ce qui évite l'analyse lexicale, l'analyse syntaxique et la compilation lors des requêtes suivantes. Il exécute également une passe d'optimisation (évaluation des constantes, suppression du code mort, fusion de codes opérationnels). La VM exécute toujours les codes opérationnels mis en cache à chaque requête : c'est à ce niveau que le JIT intervient ensuite.
Coût des appels de fonctions
Les appels empilent un nouveau cadre de pile de la VM : les codes opérationnels INIT_FCALL, SEND_VAL/SEND_VAR pour chaque argument, puis DO_FCALL. Le comprendre explique pourquoi les appels excessifs à de très petites fonctions ont un coût mesurable et pourquoi le dépliage des fonctions et le JIT sont importants dans les boucles très sollicitées.
<?php
// square($x) compiles to a call sequence:
// INIT_FCALL 'square'
// SEND_VAR $x
// DO_FCALL -> ~R
// ASSIGN $y, ~R
function square(int $x): int { return $x * $x; }
$total = 0;
for ($i = 1; $i <= 5; $i++) {
$total += square($i); // one call sequence per iteration
}
echo $total . PHP_EOL; // 1+4+9+16+25 = 55
?>Fin d'une requête
Après l'exécution, PHP démantèle la requête : les variables encore présentes sont libérées, la sortie est vidée, puis le moteur réinitialise sa zone d'allocation. Dans un modèle FPM sans partage d'état, chaque requête démarre dans un environnement propre — c'est pourquoi une erreur fatale dans une requête ne peut pas en corrompre une autre. Les tableaux de codes opérationnels partagés d'OPcache persistent d'une requête à l'autre ; l'état de l'exécuteur, lui, ne persiste pas.
Vérification rapide
Que stocke exactement OPcache pour éviter la recompilation ?
Récapitulatif
La chaîne Zend suit les étapes analyse lexicale → analyse syntaxique → compilation → exécution. Le code source devient des jetons, puis un AST, puis un tableau de codes opérationnels que parcourt la boucle d'exécution de la VM ; les variables locales sont stockées dans des emplacements CV numérotés et les appels empilent des cadres de pile. OPcache met en cache le tableau de codes opérationnels (avec une passe d'optimisation), de sorte que seule l'exécution se répète à chaque requête.
Questions Fréquemment Posées
La leçon « Fonctionnement du moteur Zend » est-elle gratuite ?
Oui — le texte complet de « Fonctionnement du moteur Zend » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours PHP Academy, passe à CoddyKit PRO. Le cours PHP Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Fonctionnement du moteur Zend » ?
Suivez PHP du code source aux opcodes, puis jusqu’à l’exécution. Tu pratiques PHP Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer PHP Academy ?
Aucune expérience préalable n'est requise. PHP Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Fonctionnement du moteur Zend » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon PHP Academy ?
Oui. Chaque leçon PHP Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Fonctionnement du moteur Zend
- Gestion de la mémoire et récupération des déchets
- OPcache et compilation JIT
- Écrire une extension PHP de base en C