Architecture du code PHP
Toutes les parties de PHP sont dans une couche appelée TSRM. La couche TSRM est responsable de la gestion de la sécurité du thread. comme la ligne de commande sapi est cli, php-fpm est le sapi de fastcgi, et le mode module d'apache est également un
noyau PHP et moteur Zend. opérations sur les fichiers, le noyau Zend est responsable de la compilation et de l'exécution/allocation de la mémoire et des ressources.
En plus de tout cela, il y a la couche d'extension. La plupart des interfaces externes en PHP sont fournies via la couche d'extension, comme. as, Les fondements du langage tels que standard et string sont également fournis sous forme d'extensions
Il existe deux façons de charger des extensions (ci-après appelées modules) dans PHP : la compilation statique, la liaison dynamique
.Compilation statique Le script configure de PHP doit être régénéré, ce qui ne sera pas décrit ici. La méthode du lien dynamique consiste à compiler le module dans un fichier .so puis à le charger dynamiquement dans PHP
. Il existe deux façons de charger le fichier .so. L'une consiste à l'écrire dans le fichier php.ini, par exemple : extension=apc.so, l'autre consiste à utiliser dl('xxx.so').
dl($library)
est de charger un module pour rendre disponible ses capacités internes. Le code source de la fonction dl() est dans le PHP. répertoire racine du code source (en abrégé PHP_SRC_HOME), PHP_SRC_HOME /ext/standard/dl.c, le processus de traitement des clés est le suivant : PHP_FUNCTION(dl)PHPAPI PHP_FUNCTION(dl) { //... php_dl(filename, MODULE_TEMPORARY, return_value, 0 TSRMLS_CC); //... }
PHPAPI void php_dl(char *file, int type, zval *return_value, int start_now TSRMLS_DC) { if (php_load_extension(file, type, start_now TSRMLS_CC) == FAILURE) { //... }
PHPAPI int php_load_extension(char *filename, int type, int start_now TSRMLS_DC) { //文件名解析相关 //加载动态链接库 handle = DL_LOAD(libpath); //加载错误处理 //获取模块的get_module函数(重点, 模块初始入口) get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module"); //get_module函数获取错误处理 //那个get_module()得到struct zend_module_entry module_entry = get_module(); //... //注册模块(重点, 函数在这里被注册) if ((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) { //错误处理 } //模块启动(重点, PHP_MINIT_FUNCTION) if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) { //错误处理 } //模块请求启动(重点, PHP_RINIT_FUNCTION) if ((type == MODULE_TEMPORARY || start_now) && module_entry->request_startup_func) { //错误处理 } return SUCCESS; }
pointeur de fonction obtenu à partir de la bibliothèque de liens dynamiques qui vient d'être chargée, qui est la fonction get_module que nous avons. défini lors du développement du module.
Après expansion de la macro (sans tenir compte des attributs pour GNU et extern "C" pour C++) : zend_module_entry *get_module(void) { return &sample_module_entry }En mettant dl() Le processus de chargement de la fonction est lié à la définition lors du développement du module. Nous pouvons voir que lorsque le module est chargé, notre zend_module_entry personnalisé est transmis à partir d'ici Inscription du module<. 🎜>module_entry = zend_register_module_ex(module_entry TSRMLS_CC)
Le code ci-dessus est extrait de la fonction php_load_extension Nous continuons à explorer zend_register_module_ex() pour trouver l'enregistrement de fonction qui nous intéresse :
if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type TSRMLS_CC)==FAILURE) {
Continuez à explorer la fonction zend_register_functions :
Récupérer la fonction Lors de la création de la table des symboles, une macro CG est utilisée :ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC) /* {{{ */ { //... //重点 如果没有函数符号表, 取全局函数符号表 if (!target_function_table) { target_function_table = CG(function_table); } //... //重点 循环zend_function_entry[] while (ptr->fname) { //向函数符号表增加函数 if (zend_hash_add(target_function_table, lowercase_name, fname_len+1, &function, sizeof(zend_function), (void**)?_function) == FAILURE) { //错误处理 } //... //准备遍历zend_function_entry[]下一个元素 ptr++; //... } //... return SUCCESS; }
target_function_table = CG(function_table);
Nous résolvons cette macro dans deux situations :
Enfin, ce qu'ils obtiennent est l'élément function_table dans une//非线程安全 compiler_globals.function_table //线程安全 (((zend_compiler_globals *) (*((void ***) tsrm_ls))[ compiler_globals_id - 1])-> function_table)
zend_compiler_globals, qui est une HashTable La boucle suivante est facile à comprendre. . Lors du développement du module, utilisez la fonction dans zend_function_entry. Vous pouvez ajouter la traversée à la HashTable
Démarrage du module/Démarrage de la demande de module
Ces deux parties sont faciles à comprendre et correspondent. à PHP_MINIT_FUNCTION() et PHP_RINIT_FUNCTION respectivement dans le développement de modules ()
.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!