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_MINIT
The 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"