Où se trouve le point d'entrée du code d'une certaine SAPI ?
El CLI est une application autonome. Comme toute autre application écrite en C, son point d'entrée est la fonction main()
(dossier sapi/cli/php_cli.c
, ligne 1200
):
int main(int argc, char *argv[])
Il existe deux versions du CLI pour Windows, l'une d'entre elles est une application console et démarre avec l'icône main()
décrite ci-dessus, l'autre est une application Windows GUI (elle ne crée pas de console au démarrage et utilise des boîtes de messages pour la sortie) qui démarre avec la fonction WinMain()
fonction (fichier sapi/cli/php_cli.c
, ligne 1198
).
main()
y WinMain()
utilisez le même code ici. Ils ont un nom différent et des fragments de code différents ici et là en vérifiant si le symbole PHP_CLI_WIN32_NO_CONSOLE
est définie. Il est défini dans le fichier sapi/cli/cli_win32.c
qui est utilisé pour générer l'application Windows GUI.
</Windows>
El CGI est également une application console autonome. Son point d'entrée est également le main()
fonction dans le fichier sapi/cgi/cgi_main.c
, ligne 1792
.
Similaire, le FPM version commence par main()
dans le fichier sapi/fpm/fpm/fpm_main.c
, ligne 1570
.
Gestionnaire Apache2 est un module chargeable dynamiquement ( .dll
sur Windows, .so
sur les systèmes de type Unix). Il enregistre certaines fonctions en tant que gestionnaires d'événements pour les événements publiés par le serveur Web (démarrage du serveur, pré/post configuration chargée, demande de processus, etc.) Ces gestionnaires sont enregistrés par la fonction php_ap2_register_hook()
fonction dans le fichier sapi/apache2handler/sapi_apache2.c
, ligne 738
.
(Vous pouvez trouver des détails sur la façon dont un module chargeable s'intègre à Apache dans le document Documentation Apache .)
Le gestionnaire qui nous intéresse est la fonction php_handler()
qui est invoqué pour traiter une requête HTTP.
De la même manière, chaque SAPI possède un point d'entrée (soit main()
ou une fonction qui est invoquée par le serveur web).
Tous ces points d'entrée effectuent un traitement similaire :
- s'initialiser ;
- analyser les arguments de la ligne de commande (seulement si c'est le cas) CLI , CGI ou tout autre type d'application autonome) ;
- lire
php.ini
et/ou toute autre configuration qu'ils ont (la configuration du module Apache peut être remplacée dans le module .htaccess
) ;
- créer un flux en utilisant le fichier d'entrée et le passer à la fonction
php_execute_script()
défini dans le fichier main/main.c
, ligne 2496
;
- nettoyer et renvoyer un code de sortie au processus appelant (le shell ou le serveur web).
Où se trouve le code qui exécute réellement un script PHP ?
La fonction php_execute_script()
est une enveloppe ; elle interprète les php.ini
entrées de configuration auto_prepend_file
y auto_append_file
prépare la liste des fichiers (fichier auto-prepend, script principal, fichier auto-append) et transmet la liste à zend_execute_scripts()
qui les traite.
php_execute_script()
n'est pas toujours invoqué, certains SAPI et arguments de ligne de commande du CLI produisent l'invocation directe de zend_execute_scripts()
.
zend_execute_scripts()
c'est là que les choses intéressantes se produisent.
Il compile le fichier PHP (et renvoie une liste de Codes OP en op_array
puis, si la compilation réussit (la valeur retournée est op_array
n'est pas NULL
) il exécute les codes OP. Il y a aussi la gestion des exceptions et le nettoyage ; un travail ennuyeux mais aussi important que l'analyse syntaxique et les exécutions.
La compilation est un processus fastidieux. Elle est effectuée par la fonction zendparse()
défini dans le fichier Zend/zend_language_parser.c
. La définition de la zendparse()
et le fichier Zend/zend_language_parser.c
ne figurent nulle part dans le répertoire Git ; l'analyseur syntaxique est généré à l'aide de la fonction bison
y re2c
qui lisent les règles syntaxiques du langage et la définition des tokens lexicaux à partir de Zend/zend_language_parser.y
y Zend/zend_language_scanner.l
et générer le compilateur actuel dans le fichier Zend/zend_language_parser.c
.
Cependant, même si le travail difficile n'est pas visible dans le repo, les parties intéressantes du processus de compilation sont visibles dans les fichiers mentionnés ci-dessus.
L'exécution du script compilé (la liste des codes OP) se fait par la fonction zend_execute()
qui est défini dans le fichier Zend/zend_vm_execute.h
. Il s'agit également d'un fichier généré et la partie intéressante est qu'il est généré par un script PHP.
Le générateur script ( Zend/zend_vm_gen.php
) utilise zend_vm_def.h
y zend_vm_execute.skl
pour générer zend_vm_execute.h
y zend_vm_opcodes.h
.
zend_vm_def.h
contient le code d'interprétation réel qui est exécuté pour traiter chaque code OP.
Où se trouve le code d'une fonction fournie par le noyau de PHP ou l'une de ses extensions ?
Le code des fonctions PHP et des fonctions fournies par les extensions est en quelque sorte plus facile à suivre. Les fonctions incluses dans le noyau de PHP sont situées dans des fichiers du répertoire ext/standard
les fonctions fournies par d'autres extensions sont situées dans des fichiers dans le répertoire correspondant ext
des sous-répertoires.
Dans ces fichiers, les fonctions C qui implémentent les fonctions PHP sont déclarées à l'aide de l'attribut PHP_FUNCTION()
macro. Par exemple, l'implémentation de la fonction PHP strpos()
commence dans le fichier ext/standard/string.c
, ligne 1948
. La fonction strchr()
étant un alias de strstr()
est déclaré à l'aide de l'élément PHP_FALIAS()
macro dans le fichier ext/standard/basic_functions.c
en ligne 2833
.
Et ainsi de suite, et ainsi de suite.