An in-depth understanding of the PHP principle's extended onboarding process

Source: Internet
Author: User
Tags register php zts
Why Xdebug extension must is loaded as a zend extension?

What's Zend extension and what is the differents between regular PHP extension and Zend extension?

Let's start from the extension loading process.

PHP is extensible, PHP's core engine Zend engines can also be extended, if you also have an understanding of the Apache module writing, then you will be familiar with the following structure:

struct _zend_extension {        char *name;        char *version;        char *author;        char *url;        char *copyright;        startup_func_t startup;        shutdown_func_t shutdown;        activate_func_t activate;        deactivate_func_t deactivate;        message_handler_func_t Message_handler;        op_array_handler_func_t Op_array_handler;        statement_handler_func_t Statement_handler;        fcall_begin_handler_func_t Fcall_begin_handler;        fcall_end_handler_func_t Fcall_end_handler;        op_array_ctor_func_t Op_array_ctor;        op_array_dtor_func_t Op_array_dtor;        Int (*api_no_check) (int api_no);        void *reserved2;        void *reserved3;        void *reserved4;        void *reserved5;        void *reserved6;        void *reserved7;        void *reserved8;        Dl_handle HANDLE;        int resource_number;};

Then, let's compare the module entry for PHP extension:

struct _zend_module_entry {unsigned short size;          unsigned int zend_api;          unsigned char zend_debug;          unsigned char zts;          struct _zend_ini_entry *ini_entry;          struct _ZEND_MODULE_DEP *deps;          Char *name;          struct _zend_function_entry *functions;          Int (*module_startup_func) (Init_func_args);          Int (*module_shutdown_func) (Shutdown_func_args);          Int (*request_startup_func) (Init_func_args);          Int (*request_shutdown_func) (Shutdown_func_args);          void (*info_func) (Zend_module_info_func_args);          Char *version;     size_t Globals_size;     #ifdef ZTS ts_rsrc_id* globals_id_ptr;     #else void* globals_ptr;          #endif void (*globals_ctor) (void *global tsrmls_dc);          void (*globals_dtor) (void *global tsrmls_dc);          Int (*post_deactivate_func) (void);          int module_started;          unsigned char type;          void *handle; int Module_number };

The above structure can be combined with my previous article to expand your PHP to help understand it in C + +.

Well, back to the topic: since xdebug to Zend extension way to load, then it must be based on the Zend extension demand, what will it be?

Well, we know Xdebug has the function of the profile PHP, yes, that's Statement_handler:
The statement handler callback inserts an additional opcode at the end of every statement in a script in which the CALLBAC K is called. One of the primary uses for this sort of callback are to implement Per-line profiling, stepping debuggers, or code-coverage Utilities.

Also, because Xdebug also provides a function for user script, it will have some implementation of PHP extension, and because it wants to load in zendext way, it must implement its own phpext part of the loading process.

Finally, the PHP extension loading process is listed as follows (I will slowly add comments), of course, if you can not wait to know, also welcome you directly in my blog in the Wind and snow to discuss the message.

Taking apache/mod_php5.c as an example

1. In mod_php5.c, the Apache module structure is defined:

Module Module_var_export php5_module = {standard_module_stuff, Php_init_handler,/* Initi Alizer */Php_create_dir,/* per-directory config Creator */php_merge_dir,/*  DIR merger */NULL,/* per-server config Creator */null,/* Merge Server config */php_commands,/* Command table */php_handlers,/* H Andlers */NULL,/* filename translation */null,/* Check_u          SER_ID */NULL,/* Check auth */null,/* Check access */                        NULL,/* Type_checker */NULL,/* fixups */null /* Logger */#if module_magic_number >= 19970103, NULL/* Header    Parser */#endif #if module_magic_number >= 19970719, NULL/* child_init */#endif #if Module_ma  Gic_number >= 19970728, php_child_exit_handler/* child_exit */#endif #if Module_magic_number >= 19970902, NULL/* Post Read-request */#endif};/*}}} */

It can be seen that the first call will be Php_init_handler,

static void Php_init_handler (Server_rec *s, pool *p) {    register_cleanup (p, NULL, (Void (*) (void *)) apache_php_module _shutdown_wrapper, (Void (*) (void *)) php_module_shutdown_for_exec);    if (!apache_php_initialized) {        apache_php_initialized = 1; #ifdef ZTS        tsrm_startup (1, 1, 0, NULL); #endif        Sapi_startup (&apache_sapi_module);        Php_apache_startup (&apache_sapi_module);    } #if module_magic_number >= 19980527    {        tsrmls_fetch ();        if (PG (expose_php)) {            ap_add_version_component ("php/" php_version);        }    } #endif}

Here, call the Sapi_startup, which is part of initializing PHP Apache SAPI,
And then the call, Php_apache_startup:

static int Php_apache_startup (Sapi_module_struct *sapi_module) {    if (Php_module_startup (Sapi_module, &apache _module_entry, 1) = = FAILURE) {        return FAILURE;    } else {        return SUCCESS;}    }

This time, call the Php_module_startup, which has:

/* This would read in php.ini, set up the configuration parameters,       load Zend Extensions and register PHP function exte Nsions to be       loaded later *    /if (php_init_config (tsrmls_c) = = FAILURE) {        return FAILURE;    }

Called Php_init_config, which reads all the php.ini and associated INI files, and then calls for each configuration instruction:

.... if (sapi_module.ini_entries) {zend_parse_ini_string (sapi_module.ini_entries, 1, PHP_CONFIG_INI_PARSER_CB, &am    p;extension_lists);                    Then in PHP_CONFIG_INI_PARSER_CB: if (!strcasecmp (Z_strval_p (arg1), "extension")) {/* Load function Module */                     Zval copy;                    copy = *arg2;                    Zval_copy_ctor (©);                    Copy.refcount = 0;                Zend_llist_add_element (&extension_lists.functions,©); } else if (!strcasecmp (Z_strval_p (arg1), Zend_extension_token)) {/* load ZEND EXTENSION */char *exten                     Sion_name = Estrndup (z_strval_p (arg2), Z_strlen_p (arg2));                Zend_llist_add_element (&extension_lists.engine, &extension_name); } else {zend_hash_update (&configuration_hash, Z_strval_p (arg1), Z_strlen_p (arg1) + 1, arg2, sizeof                    (Zval), (void * *) &entry); Z_strval_p (Entry) = Zend_strndup (Z_STRVAl_p (Entry), Z_strlen_p (entry)); }

All the PHP extension and Zend Extension to load are recorded here,
And then, let's go back to Php_module_startup, back to the call to the
Php_ini_register_extensions (Tsrmls_c);

void Php_ini_register_extensions (tsrmls_d) {    zend_llist_apply (&extension_lists.engine, Php_load_zend_ EXTENSION_CB tsrmls_cc);    Zend_llist_apply (&extension_lists.functions, PHP_LOAD_FUNCTION_EXTENSION_CB TSRMLS_CC);     Zend_llist_destroy (&extension_lists.engine);    Zend_llist_destroy (&extension_lists.functions);}

We can see that for each extended record, a callback function is called, and we only see PHP_LOAD_FUNCTION_EXTENSION_CB here:

static void Php_load_function_extension_cb (void *arg tsrmls_dc) {    Zval *extension = (Zval *) arg;    Zval Zval;     PHP_DL (extension, module_persistent, &zval, 0 tsrmls_cc);}

Finally, the core loading logic is:

void Php_dl (zval *file, int type, zval *return_value, int start_now tsrmls_dc) {void *handle;        Char *libpath;        Zend_module_entry *module_entry;        Zend_module_entry * (*get_module) (void);        int error_type;         Char *extension_dir;        if (type = = module_persistent) {Extension_dir = Ini_str ("Extension_dir");        } else {extension_dir = PG (Extension_dir);        } if (type = = module_temporary) {error_type = e_warning;        } else {error_type = e_core_warning;                 } if (Extension_dir && extension_dir[0]) {int extension_dir_len = strlen (Extension_dir); if (type = = Module_temporary) {if (STRCHR (z_strval_p (file), '/')! = NULL | | STRCHR ( Z_strval_p (file), default_slash)! = NULL) {php_error_docref (null TSRMLS_CC, e_warning, "Te    Mporary module name should contain only filename ");                            Return_false; }} if (Is_slash (extension_dir[extension_dir_len-1])) {spprintf (&am                P;libpath, 0, "%s%s", Extension_dir, z_strval_p (file));                } else {spprintf (&libpath, 0, "%s%c%s", Extension_dir, Default_slash, z_strval_p (file));        }} else {libpath = Estrndup (z_strval_p (file), z_strlen_p (file));        }/* Load dynamic symbol */handle = Dl_load (LIBPATH); if (!handle) {php_error_docref (NULL tsrmls_cc, Error_type, "Unable to load dynamic library '%s '-%s", Lib                Path, Get_dl_error ()); Get_dl_error ();                /* Free the buffer storing the error */Efree (LIBPATH);        Return_false;         } efree (LIBPATH);         Get_module = (Zend_module_entry * (*) (void)) Dl_fetch_symbol (handle, "get_module"); /* * Some OS prepend_ to symbol names and their dynamic linker * Does not does that automatically.         Thus we check manually for * _get_module. */if (!get_module) Get_module = (Zend_module_entry * (*) (void)) Dl_fetch_symbol (handle, "_get_modul         E ");                if (!get_module) {dl_unload (handle);                Php_error_docref (NULL tsrmls_cc, Error_type, "Invalid Library (maybe not a PHP library) '%s '", z_strval_p (file));        Return_false;        } module_entry = Get_module (); if ((module_entry->zend_debug! = zend_debug) | | (Module_entry->zts! = using_zts) | | (Module_entry->zend_api! = zend_module_api_no))                        {/* Check for pre-4.1.0 module which have a slightly different module_entry structure:(*/                                  struct Pre_4_1_0_module_entry {char *name;                            Zend_function_entry *functions;      Int (*module_startup_func) (Init_func_args);                                  Int (*module_shutdown_func) (Shutdown_func_args);                                  Int (*request_startup_func) (Init_func_args);                                  Int (*request_shutdown_func) (Shutdown_func_args);                                  void (*info_func) (Zend_module_info_func_args);                                  Int (*global_startup_func) (void);                                  Int (*global_shutdown_func) (void);                                  int globals_id;                                  int module_started;                                  unsigned char type;                                  void *handle;                                  int module_number;                                  unsigned char zend_debug;                                  unsigned char zts;                        unsigned int zend_api;                         };          Char *name;              int Zend_api;                         unsigned char zend_debug, zts;                                if (((struct pre_4_1_0_module_entry *) module_entry->zend_api > 20000000) && ((struct pre_4_1_0_module_entry *) module_entry)->zend_api < 20010901))                                {name = ((struct pre_4_1_0_module_entry *) module_entry)->name;                                Zend_api = ((struct pre_4_1_0_module_entry *) module_entry)->zend_api;                                Zend_debug = ((struct pre_4_1_0_module_entry *) module_entry)->zend_debug;                        Zts = ((struct pre_4_1_0_module_entry *) module_entry)->zts;                                } else {name = module_entry->name;                                Zend_api = module_entry->zend_api;        Zend_debug = module_entry->zend_debug;                        Zts = module_entry->zts; } php_error_docref (NULL tsrmls_cc, Error_type, "%s:unabl E to initialize module\n "" module compiled with module api=%d, debug=%d, thread-s                                          afety=%d\n "" PHP compiled with module api=%d, debug=%d, thread-safety=%d\n " "These options need to match\n", name, Zen                        D_api, Zend_debug, Zts, Zend_module_api_no, Zend_debug, Using_zts);                        Dl_unload (handle);        Return_false;        } module_entry->type = type;        Module_entry->module_number = Zend_next_free_module ();         Module_entry->handle = handle;   if ((Module_entry = ZEND_REGISTER_MODULE_EX (module_entry tsrmls_cc)) = = NULL) {             Dl_unload (handle);        Return_false; } if (type = = Module_temporary | | start_now) && ZEND_STARTUP_MODULE_EX (module_entry tsrmls_cc) = = FAILURE                ) {dl_unload (handle);        Return_false; } if ((type = = Module_temporary | | start_now) && module_entry->request_startup_func) {i                        F (Module_entry->request_startup_func (type, module_entry->module_number tsrmls_cc) = = FAILURE) {                        Php_error_docref (NULL tsrmls_cc, Error_type, "Unable to initialize module '%s ', module_entry->name);                        Dl_unload (handle);                Return_false; }} return_true;}
  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.