Home >Backend Development >PHP Problem >How to customize PHP extension (2) hook function

How to customize PHP extension (2) hook function

藏色散人
藏色散人forward
2021-12-20 15:51:322115browse

Following previous article let’s talk about the php life cycle and see which hooks are extended to do what, php There are about 5 stages in the life cycle, module initialization stagephp_module_startup, request initialization stagephp_request_startup, script execution stagephp_execute_script, request shutdown stagephp_request_shutdown ,Module shutdown phasephp_module_shutdown, introduced below in cli mode.

php_module_startup

First take a look at what is done at this stage. If you don’t know where the php entry file is, use gdb to look at the call stack, gdb ./ php

At the php_module_startup break point, execute, look at the call stack,

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

You can clearly see the execution process in the call stack, now go to/ main/main.c file to see what has been done. You can also use gdb to see it step by step. Here are a few places related to PHP extensions. The initialization work done here, such as garbage collection, request initialization, and registered constants. php.ini configuration file loading, etc.

Let’s first look at how to load the module

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

Here is to load the built-in module of php. Only the core functions are posted here. Check the dependencies first

/* 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;
        }
    }
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;
    }

This is the principle of loading built-in modules. Now let’s see how to load the extension in ini

php_ini_register_extensions();
zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb);

Use this function to load

php_load_extension(char *filename, int type, int start_now)

This also performs the function of loading built-in modules.

is calling module->functions to register the module function function. Now we know why the function function should be written in helloworld_functions here

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
};

Now look at several hook functions of the extension

/* start Zend extensions */
    zend_startup_extensions();

The core here isfunc(element->data)That is, executing the extension

PHP_MINIT Function

element=l->head;
    while (element) {
        next = element->next;
        if (func(element->data)) {
            DEL_LLIST_ELEMENT(element, l);
        }
        element = next;
    }

Now we know thatPHP_MINITThe hook can do many initialization functions. How to register a custom extended function class and how to write the extended variables into php.ini , how to rewrite php built-in functions,

original = zend_hash_str_find_ptr(CG(function_table), "var_dump", sizeof("var_dump")-1);

    if (original != NULL) {

        original->internal_function.handler = my_overwrite_var_dump;
    }

    zend_class_entry person;
    INIT_CLASS_ENTRY(person,CLASS_NAME,person_functions);
    zend_register_internal_class_ex(&person,NULL);

Here is to rewrite the var_dump function, register a person class, introduce it here first, Next article will introduce how to pass php code through lexical analysis Syntax analysis generates AST, and then compiles opcode instructions for call by zend virtual machine.

Recommended learning: "PHP Video Tutorial"

The above is the detailed content of How to customize PHP extension (2) hook function. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete