PHP扩展的加载流程

第一步,先完成一个最简单的扩展,只提供一个函数,hello。

主要代码:

ZEND_FUNCTION(hello)
{
    php_printf( " Hello World!\n ");
}

static zend_function_entry tonic_functions[] = {
    ZEND_FE(hello,        NULL)
    { NULL, NULL, NULL }
};

zend_module_entry tonic_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
     STANDARD_MODULE_HEADER,
#endif
     " tonic "
    tonic_functions,  /*  Functions  */
    NULL,  /*  MINIT  */
    NULL,  /*  MSHUTDOWN  */
    NULL,  /*  RINIT  */
    NULL,  /*  RSHUTDOWN  */
    NULL,  /*  MINFO  */
#if ZEND_MODULE_API_NO >= 20010901
     " 2.1 "
#endif
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_TONIC
ZEND_GET_MODULE(tonic)

#endif 

  

这几行代码,就完成了一个最简单的扩展了...


 ZEND_GET_MODULE宏展开如下:

#define ZEND_GET_MODULE(name) \
    BEGIN_EXTERN_C()\
    ZEND_DLEXPORT zend_module_entry *get_module( void) {  return &name##_module_entry; }\

    END_EXTERN_C() 

 这个宏,定义了一个名为get_module的函数,返回当前模块定义的zend_module_entry的指针。(通过这个宏可以发现,module_entry的名称,是固定格式的..不然就要自己实现get_module函数)

 

再看看php加载扩展的实现(我去掉了一些老版本兼容等与分析无关的代码) :

PHPAPI  int php_load_extension( char *filename,  int type,  int start_now TSRMLS_DC)  /*  {{{  */
{
     void *handle;
     char *libpath;
    zend_module_entry *module_entry;
    zend_module_entry *(*get_module)( void); /* 函数指针,获取module的信息 */
     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;
    }

     /*  Check if passed filename contains directory separators  */
     if (strchr(filename,  ' / ') != NULL || strchr(filename, DEFAULT_SLASH) != NULL) {
         /*  Passing modules with full path is not supported for dynamically loaded extensions  */
         if (type == MODULE_TEMPORARY) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING,  " Temporary module name should contain only filename ");
             return FAILURE;
        }
        libpath = estrdup(filename);
    }  else  if (extension_dir && extension_dir[ 0]) {
         int extension_dir_len = strlen(extension_dir);

         if (IS_SLASH(extension_dir[extension_dir_len- 1])) {
            spprintf(&libpath,  0" %s%s ", extension_dir, filename);  /*  SAFE  */
        }  else {
            spprintf(&libpath,  0" %s%c%s ", extension_dir, DEFAULT_SLASH, filename);  /*  SAFE  */
        }
    }  else {
         return FAILURE;  /*  Not full path given or extension_dir is not set  */
    }

     /*  load dynamic symbol  */
    handle = DL_LOAD(libpath); /* 加载动态链接文件 */
     if (!handle) {
        php_error_docref(NULL TSRMLS_CC, error_type,  " Unable to load dynamic library '%s' - %s ", libpath, GET_DL_ERROR());
        GET_DL_ERROR();  /*  free the buffer storing the error  */

        efree(libpath);
         return FAILURE;
    }
    efree(libpath);

    get_module = (zend_module_entry *(*)( void)) DL_FETCH_SYMBOL(handle,  " get_module ");/* 获取动态链接库内部实现的get_module函数的指针供下面调用  */

     /*  Some OS prepend _ to symbol names while their dynamic linker
     * does not do that automatically. Thus we check manually for
     * _get_module. 
*/

     if (!get_module) {
        get_module = (zend_module_entry *(*)( void)) DL_FETCH_SYMBOL(handle,  " _get_module ");
    }

     if (!get_module) { /* 如果动态链接库没有实现get_module函数,或者函数原型与前面定义的不符,则不是合法的PHP扩展 */
        DL_UNLOAD(handle);
        php_error_docref(NULL TSRMLS_CC, error_type,  " Invalid library (maybe not a PHP library) '%s' ", filename);
         return FAILURE;
    }
    module_entry = get_module();/* 执行get_module函数,获取zend_module_entry的信息,这里是个指针 */
    
    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) {  /* 这里完成三个任务,第一判断此扩展依赖的其它扩展是否都已经正确加载,第二将扩展的module_entry添加到全局的module_registry这个HashTable中,第三,注册扩展提供的所有函数 */
        DL_UNLOAD(handle);
         return FAILURE;
    }

     if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) { /* 执行module_entry的MINIT函数 */
        DL_UNLOAD(handle);
         return FAILURE;
    }

     if ((type == MODULE_TEMPORARY || start_now) && module_entry->request_startup_func) {
         if (module_entry->request_startup_func(type, module_entry->module_number TSRMLS_CC) == FAILURE) { /* 执行module_entry的RINIT函数 */
            php_error_docref(NULL TSRMLS_CC, error_type,  " Unable to initialize module '%s' ", module_entry->name);
            DL_UNLOAD(handle);
             return FAILURE;
        }
    }
     return SUCCESS;

你可能感兴趣的:(PHP)