Comment personnaliser la fonction de hook de l'extension PHP (2)

藏色散人
Libérer: 2023-03-14 14:32:01
avant
2074 Les gens l'ont consulté

Dans la continuité de l'article précédent parlons du cycle de vie de php et voyons quels hooks sont étendus pour faire quoi. Le cycle de vie de php comporte environ 5 étapes, l'étape d'initialisation du module php_module_startup code>, phase d'initialisation de la demande <code>php_request_startup, phase d'exécution du script php_execute_script, phase d'arrêt de la demande php_request_shutdown, phase d'arrêt du module php_module_shutdown , ce qui suit est introduit en mode cli. php_module_startup,请求初始化阶段php_request_startup,脚本执行阶段php_execute_script,请求关闭阶段php_request_shutdown,模块关闭阶段php_module_shutdown,下面以cli模式介绍。

php_module_startup

先看看这个阶段做了什么,如果不知道php入口文件在哪,用gdb看看调用栈,gdb ./php

php_module_startup打断点,执行,在看下调用栈,

b php_module_startup
(gdb) r test.php
bt
php_module_startup (sf=0x1406460 <cli_sapi_module>, 
    additional_modules=0x0, num_additional_modules=0)
    at /www/test/php/php-7.4.3/main/main.c:2098
#1  0x00000000008bae7c in php_cli_startup (
    sapi_module=0x1406460 <cli_sapi_module>)
    at /www/test/php/php-7.4.3/sapi/cli/php_cli.c:407
#2  0x00000000008bcc80 in main (argc=2, argv=0x1425af0)
    at /www/test/php/php-7.4.3/sapi/cli/php_cli.c:1323
Copier après la connexion

在调用栈可以清楚看到执行流程,现在到/main/main.c文件看看做了哪些事情,也可以用gdb一步一步的看,这里就讲与php扩展有关的几个地方,这里做的初始化工作,像垃圾回收,请求初始化,注册常量,php.ini配置文件加载等,

先来看看怎么加载模块的

/* startup extensions statically compiled in */
    if (php_register_internal_extensions_func() == FAILURE) {
        php_printf("Unable to start builtin modules\n");
        return FAILURE;
    }
Copier après la connexion

这里是加载php内置的模块,这里只贴出核心功能,先检查依赖

/* Check module dependencies */
    if (module->deps) {
        const zend_module_dep *dep = module->deps;

        while (dep->name) {
            if (dep->type == MODULE_DEP_CONFLICTS) {
                name_len = strlen(dep->name);
                lcname = zend_string_alloc(name_len, 0);
                zend_str_tolower_copy(ZSTR_VAL(lcname), dep->name, name_len);

                if (zend_hash_exists(&module_registry, lcname) || zend_get_extension(dep->name)) {
                    zend_string_efree(lcname);
                    /* TODO: Check version relationship */
                    zend_error(E_CORE_WARNING, "Cannot load module '%s' because conflicting module '%s' is already loaded", module->name, dep->name);
                    return NULL;
                }
                zend_string_efree(lcname);
            }
            ++dep;
        }
    }
Copier après la connexion
if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type)==FAILURE) {
        zend_hash_del(&module_registry, lcname);
        zend_string_release(lcname);
        EG(current_module) = NULL;
        zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load", module->name);
        return NULL;
    }
Copier après la connexion

这是内置模块加载原理,现在看看ini里的扩展怎么加载

php_ini_register_extensions();
Copier après la connexion
zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb);
Copier après la connexion

利用这个函数加载

php_load_extension(char *filename, int type, int start_now)
Copier après la connexion

这里面也执行了加载内置模块的功能。

是调用了module->functions,进行模块功能函数注册,现在知道了为什么功能函数要写在helloworld_functions这里吧

zend_module_entry helloworld_module_entry = {
    STANDARD_MODULE_HEADER,
    "helloworld",                    /* Extension name */
    helloworld_functions,            /* zend_function_entry */
    PHP_MINIT(helloworld),                            /* PHP_MINIT - Module initialization */
    NULL,                            /* PHP_MSHUTDOWN - Module shutdown */
    PHP_RINIT(helloworld),            /* PHP_RINIT - Request initialization */
    NULL,                            /* PHP_RSHUTDOWN - Request shutdown */
    PHP_MINFO(helloworld),            /* PHP_MINFO - Module info */
    PHP_HELLOWORLD_VERSION,        /* Version */
    PHP_MODULE_GLOBALS(pib),
    NULL,
    NULL,
    NULL,
    STANDARD_MODULE_PROPERTIES_EX
};
Copier après la connexion

现在看看扩展的几个钩子函数

/* start Zend extensions */
    zend_startup_extensions();
Copier après la connexion

这里的核心就是func(element->data)也就是执行扩展

PHP_MINIT函数

element=l->head;
    while (element) {
        next = element->next;
        if (func(element->data)) {
            DEL_LLIST_ELEMENT(element, l);
        }
        element = next;
    }
Copier après la connexion

现在就知道PHP_MINIT

php_module_startup

Jetez d'abord un œil à ce qui est fait à ce stade. Si vous ne savez pas où se trouve le fichier d'entrée php, utilisez gdb pour regarder la pile d'appels gdb ./phpcode>

Dans php_module_startup Point d'arrêt, exécutez, regardez la pile d'appels,

Vous pouvez voir clairement le processus d'exécution dans la pile d'appels, allez maintenant dans le fichier /main/main.c pour voir ce qui a été fait, vous pouvez également utiliser gdb pour étape. Prenons une vue étape par étape. Voici quelques éléments liés aux extensions PHP effectuées ici, telles que le garbage collection, l'initialisation des requêtes, les constantes d'enregistrement. , chargement du fichier de configuration php.ini, etc.

Voyons d'abord comment charger les modules 🎜rrreee🎜Voici le chargement du module intégré de php. Seules les fonctions principales sont publiées ici. rrreeerrreee🎜C'est le principe du chargement du module intégré. Voyons maintenant comment charger l'extension dans ini🎜rrreeerrreee🎜Utilisez cette fonction pour charger🎜rrreee🎜 La fonction de chargement des modules intégrés est également réalisée ici. 🎜🎜Il s'appelle module->functions pour enregistrer la fonction de fonction du module. Nous savons maintenant pourquoi la fonction de fonction doit être écrite ici dans helloworld_functions🎜rrreee🎜Maintenant, regardez. l'extension Plusieurs fonctions de hook 🎜rrreee🎜Le noyau ici est func(element->data), qui est l'extension d'exécution 🎜🎜Fonction PHP_MINIT🎜rrreee🎜Sachez-le maintenant Le hook PHP_MINIT peut exécuter de nombreuses fonctions d'initialisation. Comment enregistrer une classe de fonctions étendues personnalisée, comment écrire des variables étendues dans php.ini, comment réécrire les fonctions intégrées PHP, 🎜rrreee🎜Voici la réécriture du. La fonction var_dump enregistre une classe de personne. Nous la présenterons ici en premier. Le prochain article expliquera comment générer AST via l'analyse lexicale et l'analyse syntaxique du code PHP, puis compiler les instructions d'opcode à appeler par la machine virtuelle zend. 🎜🎜Apprentissage recommandé : "🎜Tutoriel vidéo PHP🎜"🎜🎜

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:segmentfault.com
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!