php-5.6.26源代码 - 扩展模块的加载、注册

 

// main实现在文件 php-5.6.26\sapi\cgi\cgi_main.c
int main(int argc, char *argv[])
{
    ....
    
    cgi_sapi_module->startup(){
    
        // php_cgi_startup实现在文件 php-5.6.26\sapi\cgi\cgi_main.c
        static int php_cgi_startup(sapi_module_struct *sapi_module)
        {
            // php_module_startup实现在文件 php-5.6.26\main\main.c
            if (php_module_startup(sapi_module, &cgi_module_entry, 1){
                ....
                // 启动zend引擎(创建“全局函数表”、“全局类表”、“全局常量表”、“模块注册表”......)
                zend_startup(&zuf, NULL TSRMLS_CC); // !!!!
                ...
                // 注册常量
                REGISTER_MAIN_STRINGL_CONSTANT("PHP_VERSION", PHP_VERSION, sizeof(PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS); // 注册到  EG(zend_constants)  
                REGISTER_MAIN_LONG_CONSTANT("PHP_MAJOR_VERSION", PHP_MAJOR_VERSION, CONST_PERSISTENT | CONST_CS);
                REGISTER_MAIN_LONG_CONSTANT("PHP_MINOR_VERSION", PHP_MINOR_VERSION, CONST_PERSISTENT | CONST_CS);
                REGISTER_MAIN_LONG_CONSTANT("PHP_RELEASE_VERSION", PHP_RELEASE_VERSION, CONST_PERSISTENT | CONST_CS);
                REGISTER_MAIN_STRINGL_CONSTANT("PHP_EXTRA_VERSION", PHP_EXTRA_VERSION, sizeof(PHP_EXTRA_VERSION) - 1, CONST_PERSISTENT | CONST_CS);
                REGISTER_MAIN_LONG_CONSTANT("PHP_VERSION_ID", PHP_VERSION_ID, CONST_PERSISTENT | CONST_CS);
                ...
                php_binary_init(TSRMLS_C); // 执行文件的地址放入 PG(php_binary) = sapi_module.executable_location
                ...
                php_output_register_constants(TSRMLS_C); // 注册常量 PHP_OUTPUT_HANDLER_START 等...
                php_rfc1867_register_constants(TSRMLS_C); // 注册常量 UPLOAD_ERR_OK 等...
            
                /* this will read in php.ini, set up the configuration parameters,
                   load zend extensions and register php function extensions
                   to be loaded later */
                if (php_init_config(TSRMLS_C) == FAILURE) {  // !!!! 解析 php.ini 文件,加载zend扩展
                    return FAILURE;
                }
            
                /* Register PHP core ini entries */
                REGISTER_INI_ENTRIES();  // 设置php核心的ini配置  zend_register_ini_entries(ini_entries, module_number TSRMLS_CC)
            
                /* Register Zend ini entries */
                zend_register_standard_ini_entries(TSRMLS_C); // 设置zend的ini的配置
                
                ....
                
                php_startup_auto_globals(TSRMLS_C); // 注册"_GET"、"_POST"、"_COOKIE"、"_SERVER"的处理函数到CG(auto_globals)
                zend_set_utility_values(&zuv);
                php_startup_sapi_content_types(TSRMLS_C); // 设置sapi_module.default_post_reader sapi_module.xxx 的值
            
                /* startup extensions statically compiled in */
                // php_register_internal_extensions   php_register_extensions
                if (php_register_internal_extensions_func(TSRMLS_C) == FAILURE) {  // 迭代“内建模块列表”,添加内建模块信息到“模块注册表module_registry”、注册“模块的函数”到 CG(function_table)  
                    php_printf("Unable to start builtin modules\n");
                    return FAILURE;
                }
            
                /* start additional PHP extensions */
                php_register_extensions_bc(additional_modules, num_additional_modules TSRMLS_CC); // 添加additional_modules模块信息到“模块注册表module_registry”、注册“模块的函数”到 CG(function_table)
            
                /* load and startup extensions compiled as shared objects (aka DLLs)
                   as requested by php.ini entries
                   theese are loaded after initialization of internal extensions
                   as extensions *might* rely on things from ext/standard
                   which is always an internal extension and to be initialized
                   ahead of all other internals
                 */
                // php_ini_register_extensions实现在文件 php-5.6.26\main\php_ini.c
                php_ini_register_extensions(TSRMLS_C); // 1、加载引擎的扩展模块,并把扩展信息添加到链表 zend_extensions 中(php.ini中以zend_extension开头的配置,如zend_extension=test.so)   2、加载extension_dir用户扩展模块,并把模块信息添加到模块注册表module_registry中 (php.ini中以extension开头的配置,如extension=test.so)
                {
                    // 加载引擎的扩展模块,并把扩展信息添加到链表 zend_extensions 中(php.ini中以zend_extension开头的配置,如zend_extension=test.so)
                    zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb TSRMLS_CC); 
                    {
                        // php_ini_register_extensions实现在文件 php-5.6.26\main\php_ini.c
                        static void php_load_zend_extension_cb(void *arg TSRMLS_DC)
                        {
                            char *filename = *((char **) arg); // 扩展名
                            int length = strlen(filename);
                        
                            if (IS_ABSOLUTE_PATH(filename, length)) {
                                
                                // zend_load_extension实现在文件 php-5.6.26\Zend\zend_extensions.c
                                zend_load_extension(filename); // 把扩展添加到链表zend_extensions中
                                {
                                    int zend_load_extension(const char *path)
                                    {
                                    #if ZEND_EXTENSIONS_SUPPORT
                                        DL_HANDLE handle;
                                        zend_extension *new_extension;
                                        zend_extension_version_info *extension_version_info;
                                    
                                        handle = DL_LOAD(path);  //  加载动态链接库
                                        if (!handle) {
                                    #ifndef ZEND_WIN32
                                            fprintf(stderr, "Failed loading %s:  %s\n", path, DL_ERROR());
                                    /* See http://support.microsoft.com/kb/190351 */
                                    #ifdef PHP_WIN32
                                            fflush(stderr);
                                    #endif
                                    #else
                                            fprintf(stderr, "Failed loading %s\n", path);
                                    #endif
                                            return FAILURE;
                                        }
                                    
                                        extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info"); // 获取扩展版本信息
                                        if (!extension_version_info) {
                                            extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info");
                                        }
                                        new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry"); // !!! 扩展的固定入口
                                        if (!new_extension) {
                                            new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "_zend_extension_entry");
                                        }
                                        if (!extension_version_info || !new_extension) {
                                            fprintf(stderr, "%s doesn't appear to be a valid Zend extension\n", path);
                                    /* See http://support.microsoft.com/kb/190351 */
                                    #ifdef PHP_WIN32
                                            fflush(stderr);
                                    #endif
                                            DL_UNLOAD(handle);
                                            return FAILURE;
                                        }
                                    
                                    
                                        /* allow extension to proclaim compatibility with any Zend version */ // 扩展的版本信息
                                        if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) {
                                            if (extension_version_info->zend_extension_api_no > ZEND_EXTENSION_API_NO) {
                                                fprintf(stderr, "%s requires Zend Engine API version %d.\n"
                                                        "The Zend Engine API version %d which is installed, is outdated.\n\n",
                                                        new_extension->name,
                                                        extension_version_info->zend_extension_api_no,
                                                        ZEND_EXTENSION_API_NO);
                                    /* See http://support.microsoft.com/kb/190351 */
                                    #ifdef PHP_WIN32
                                                fflush(stderr);
                                    #endif
                                                DL_UNLOAD(handle);
                                                return FAILURE;
                                            } else if (extension_version_info->zend_extension_api_no < ZEND_EXTENSION_API_NO) {
                                                fprintf(stderr, "%s requires Zend Engine API version %d.\n"
                                                        "The Zend Engine API version %d which is installed, is newer.\n"
                                                        "Contact %s at %s for a later version of %s.\n\n",
                                                        new_extension->name, // 扩展名称
                                                        extension_version_info->zend_extension_api_no,
                                                        ZEND_EXTENSION_API_NO,
                                                        new_extension->author, // 扩展作者
                                                        new_extension->URL, // 扩展地址
                                                        new_extension->name);
                                    /* See http://support.microsoft.com/kb/190351 */
                                    #ifdef PHP_WIN32
                                                fflush(stderr);
                                    #endif
                                                DL_UNLOAD(handle);
                                                return FAILURE;
                                            }
                                        } else if (strcmp(ZEND_EXTENSION_BUILD_ID, extension_version_info->build_id) &&
                                                   (!new_extension->build_id_check || new_extension->build_id_check(ZEND_EXTENSION_BUILD_ID) != SUCCESS)) {
                                            fprintf(stderr, "Cannot load %s - it was built with configuration %s, whereas running engine is %s\n",
                                                        new_extension->name, extension_version_info->build_id, ZEND_EXTENSION_BUILD_ID);
                                    /* See http://support.microsoft.com/kb/190351 */
                                    #ifdef PHP_WIN32
                                            fflush(stderr);
                                    #endif
                                            DL_UNLOAD(handle);
                                            return FAILURE;
                                        } else if (zend_get_extension(new_extension->name)) {
                                            fprintf(stderr, "Cannot load %s - extension already loaded\n", new_extension->name);
                                    /* See http://support.microsoft.com/kb/190351 */
                                    #ifdef PHP_WIN32
                                            fflush(stderr);
                                    #endif
                                            DL_UNLOAD(handle);
                                            return FAILURE;
                                        }
                                    
                                        return zend_register_extension(new_extension, handle); // !!!注册扩展信息,并迭代执行“类似zend_extension=test.so模块”的 message_handler 方法
                                    #else
                                        fprintf(stderr, "Extensions are not supported on this platform.\n");
                                    /* See http://support.microsoft.com/kb/190351 */
                                    #ifdef PHP_WIN32
                                        fflush(stderr);
                                    #endif
                                        return FAILURE;
                                    #endif
                                    }
                                }
                            } else {
                                char *libpath;
                                char *extension_dir = INI_STR("extension_dir"); // 扩展目录
                                int extension_dir_len = strlen(extension_dir);
                        
                                if (IS_SLASH(extension_dir[extension_dir_len-1])) {
                                    spprintf(&libpath, 0, "%s%s", extension_dir, filename);
                                } else {
                                    spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, filename);
                                }
                                zend_load_extension(libpath);
                                efree(libpath);
                            }
                        }
                    }
                    
                    // 加载extension_dir用户扩展模块,并把模块信息添加到模块注册表module_registry中 (php.ini中以extension开头的配置,如extension=test.so)
                    zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb TSRMLS_CC);  
                    {
                        // php_load_php_extension_cb 实现在文件 php-5.6.26\main\php_ini.c
                        static void php_load_php_extension_cb(void *arg TSRMLS_DC)
                        {
                        #ifdef HAVE_LIBDL
                            // php_load_extension 实现在文件 php-5.6.26\ext\standard\dl.c
                            php_load_extension(*((char **) arg), MODULE_PERSISTENT, 0 TSRMLS_CC);
                        #endif
                            {
                                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;
                                }
                            
                                /* 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); // 加载test.so文件
                                if (!handle) {
                            #if PHP_WIN32
                                    char *err = GET_DL_ERROR();
                                    if (err && (*err != "")) {
                                        php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s", libpath, err);
                                        LocalFree(err);
                                    } else {
                                        php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s", libpath, "Unknown reason");
                                    }
                            #else
                                    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 */
                            #endif
                                    efree(libpath);
                                    return FAILURE;
                                }
                                efree(libpath);
                            
                                get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "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) {
                                    if (DL_FETCH_SYMBOL(handle, "zend_extension_entry") || DL_FETCH_SYMBOL(handle, "_zend_extension_entry")) {
                                        DL_UNLOAD(handle);
                                        php_error_docref(NULL TSRMLS_CC, error_type, "Invalid library (appears to be a Zend Extension, try loading using zend_extension=%s from php.ini)", filename);
                                        return FAILURE;
                                    }
                                    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(); // 取得模块信息
                                if (module_entry->zend_api != ZEND_MODULE_API_NO) {
                                    /* Check for pre-4.1.0 module which has 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;
                                        };
                            
                                        const char *name;
                                        int zend_api;
                            
                                        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;
                                        } else {
                                            name        = module_entry->name;
                                            zend_api    = module_entry->zend_api;
                                        }
                            
                                        php_error_docref(NULL TSRMLS_CC, error_type,
                                                "%s: Unable to initialize module\n"
                                                "Module compiled with module API=%d\n"
                                                "PHP    compiled with module API=%d\n"
                                                "These options need to match\n",
                                                name, zend_api, ZEND_MODULE_API_NO);
                                        DL_UNLOAD(handle);
                                        return FAILURE;
                                }
                                if(strcmp(module_entry->build_id, ZEND_MODULE_BUILD_ID)) {
                                    php_error_docref(NULL TSRMLS_CC, error_type,
                                            "%s: Unable to initialize module\n"
                                            "Module compiled with build ID=%s\n"
                                            "PHP    compiled with build ID=%s\n"
                                            "These options need to match\n",
                                            module_entry->name, module_entry->build_id, ZEND_MODULE_BUILD_ID);
                                    DL_UNLOAD(handle);
                                    return FAILURE;
                                }
                                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)){
                                
                                    // zend_register_module_ex 实现在文件 php-5.6.26\Zend\zend_API.c
                                    ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module TSRMLS_DC) /* {{{ */
                                    {
                                        int name_len;
                                        char *lcname;
                                        zend_module_entry *module_ptr;
                                    
                                        if (!module) {
                                            return NULL;
                                        }
                                    
                                    #if 0
                                        zend_printf("%s: Registering module %d\n", module->name, module->module_number);
                                    #endif
                                    
                                        /* 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_str_tolower_dup(dep->name, name_len);
                                    
                                                    if (zend_hash_exists(&module_registry, lcname, name_len+1)) { // 模块是否已经注册
                                                        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;
                                                    }
                                                    efree(lcname);
                                                }
                                                ++dep;
                                            }
                                        }
                                    
                                        name_len = strlen(module->name);
                                        lcname = zend_str_tolower_dup(module->name, name_len);
                                    
                                        if (zend_hash_add(&module_registry, lcname, name_len+1, (void *)module, sizeof(zend_module_entry), (void**)&module_ptr)==FAILURE) { // 添加模块信息到“模块注册表module_registry”
                                            zend_error(E_CORE_WARNING, "Module '%s' already loaded", module->name);
                                            efree(lcname);
                                            return NULL;
                                        }
                                        efree(lcname);
                                        module = module_ptr;
                                        EG(current_module) = module; // 当前模块
                                    
                                        // 注册扩展模块的函数
                                        if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type TSRMLS_CC){
                                            ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC) /* {{{ */
                                            {
                                                const zend_function_entry *ptr = functions; // 要注册的“模块的函数列表”
                                                zend_function function, *reg_function; // zend_function联合体
                                                zend_internal_function *internal_function = (zend_internal_function *)&function; // internal_function描述扩展模块中每个函数的信息
                                                int count=0, unload=0;
                                                HashTable *target_function_table = function_table;
                                                int error_type;
                                                zend_function *ctor = NULL, *dtor = NULL, *clone = NULL, *__get = NULL, *__set = NULL, *__unset = NULL, *__isset = NULL, *__call = NULL, *__callstatic = NULL, *__tostring = NULL, *__debugInfo = NULL;
                                                const char *lowercase_name;
                                                int fname_len;
                                                const char *lc_class_name = NULL;
                                                int class_name_len = 0;
                                                zend_ulong hash;
                                            
                                                if (type==MODULE_PERSISTENT) {
                                                    error_type = E_CORE_WARNING;
                                                } else {
                                                    error_type = E_WARNING;
                                                }
                                            
                                                if (!target_function_table) { // 如果没有指定target_function_table,那么默认填充到CG(v)
                                                    target_function_table = CG(function_table); // !!! 
                                                }
                                                internal_function->type = ZEND_INTERNAL_FUNCTION; // 函数类型
                                                internal_function->module = EG(current_module); // 所属模块
                                            
                                                if (scope) {
                                                    class_name_len = strlen(scope->name); // 类名
                                                    if ((lc_class_name = zend_memrchr(scope->name, '\\', class_name_len))) {
                                                        ++lc_class_name;
                                                        class_name_len -= (lc_class_name - scope->name);
                                                        lc_class_name = zend_str_tolower_dup(lc_class_name, class_name_len);
                                                    } else {
                                                        lc_class_name = zend_str_tolower_dup(scope->name, class_name_len);
                                                    }
                                                }
                                            
                                                while (ptr->fname) { // 函数名称 
                                                    internal_function->handler = ptr->handler; // 函数指针,等价function->handler = ptr->handler;
                                                    internal_function->function_name = (char*)ptr->fname; // 函数名
                                                    internal_function->scope = scope; // 函数的作用域
                                                    internal_function->prototype = NULL;
                                                    if (ptr->flags) {
                                                        if (!(ptr->flags & ZEND_ACC_PPP_MASK)) {
                                                            if (ptr->flags != ZEND_ACC_DEPRECATED || scope) {
                                                                zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? scope->name : "", scope ? "::" : "", ptr->fname);
                                                            }
                                                            internal_function->fn_flags = ZEND_ACC_PUBLIC | ptr->flags;
                                                        } else {
                                                            internal_function->fn_flags = ptr->flags;
                                                        }
                                                    } else {
                                                        internal_function->fn_flags = ZEND_ACC_PUBLIC;
                                                    }
                                                    if (ptr->arg_info) { // 函数的参数信息
                                                        zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info;
                                            
                                                        internal_function->arg_info = (zend_arg_info*)ptr->arg_info+1;
                                                        internal_function->num_args = ptr->num_args;
                                                        /* Currently you cannot denote that the function can accept less arguments than num_args */
                                                        if (info->required_num_args == -1) {
                                                            internal_function->required_num_args = ptr->num_args;
                                                        } else {
                                                            internal_function->required_num_args = info->required_num_args;
                                                        }
                                                        if (info->return_reference) {
                                                            internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
                                                        }
                                                        if (ptr->arg_info[ptr->num_args].is_variadic) {
                                                            internal_function->fn_flags |= ZEND_ACC_VARIADIC;
                                                        }
                                                    } else {
                                                        internal_function->arg_info = NULL;
                                                        internal_function->num_args = 0;
                                                        internal_function->required_num_args = 0;
                                                    }
                                                    if (ptr->flags & ZEND_ACC_ABSTRACT) {
                                                        if (scope) {
                                                            /* This is a class that must be abstract itself. Here we set the check info. */
                                                            scope->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
                                                            if (!(scope->ce_flags & ZEND_ACC_INTERFACE)) {
                                                                /* Since the class is not an interface it needs to be declared as a abstract class. */
                                                                /* Since here we are handling internal functions only we can add the keyword flag. */
                                                                /* This time we set the flag for the keyword 'abstract'. */
                                                                scope->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
                                                            }
                                                        }
                                                        if (ptr->flags & ZEND_ACC_STATIC && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
                                                            zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? scope->name : "", scope ? "::" : "", ptr->fname);
                                                        }
                                                    } else {
                                                        if (scope && (scope->ce_flags & ZEND_ACC_INTERFACE)) {
                                                            efree((char*)lc_class_name);
                                                            zend_error(error_type, "Interface %s cannot contain non abstract method %s()", scope->name, ptr->fname);
                                                            return FAILURE;
                                                        }
                                                        if (!internal_function->handler) {
                                                            if (scope) {
                                                                efree((char*)lc_class_name);
                                                            }
                                                            zend_error(error_type, "Method %s%s%s() cannot be a NULL function", scope ? scope->name : "", scope ? "::" : "", ptr->fname);
                                                            zend_unregister_functions(functions, count, target_function_table TSRMLS_CC);
                                                            return FAILURE;
                                                        }
                                                    }
                                                    fname_len = strlen(ptr->fname); // 函数名称
                                                    lowercase_name = zend_new_interned_string(zend_str_tolower_dup(ptr->fname, fname_len), fname_len + 1, 1 TSRMLS_CC);
                                                    hash = str_hash(lowercase_name, fname_len); // 生成hash值
                                            
                                                    // 注册函数到HashTable 类型的CG(function_table)中
                                                    if (zend_hash_quick_add(target_function_table, lowercase_name, fname_len+1, hash, &function, sizeof(zend_function), (void**)&reg_function) == FAILURE) { 
                                                        unload=1;
                                                        str_efree(lowercase_name);
                                                        break;
                                                    }
                                            
                                                    /* If types of arguments have to be checked */
                                                    if (reg_function->common.arg_info && reg_function->common.num_args) {
                                                        int i;
                                                        for (i = 0; i < reg_function->common.num_args; i++) {
                                                            if (reg_function->common.arg_info[i].class_name ||
                                                                reg_function->common.arg_info[i].type_hint) {
                                                                reg_function->common.fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
                                                                break;
                                                            }
                                                        }
                                                    }
                                            
                                                    if (scope) {
                                                        /* Look for ctor, dtor, clone
                                                         * If it's an old-style constructor, store it only if we don't have
                                                         * a constructor already.
                                                         */
                                                        if ((fname_len == class_name_len) && !ctor && !memcmp(lowercase_name, lc_class_name, class_name_len+1)) {
                                                            ctor = reg_function; // 函数名是"类名"
                                                        } else if ((fname_len == sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME) - 1)) {
                                                            ctor = reg_function; // 函数名是"__construct"
                                                        } else if ((fname_len == sizeof(ZEND_DESTRUCTOR_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_DESTRUCTOR_FUNC_NAME, sizeof(ZEND_DESTRUCTOR_FUNC_NAME) - 1)) {
                                                            dtor = reg_function; // 函数名是"__destruct"
                                                            if (internal_function->num_args) {
                                                                zend_error(error_type, "Destructor %s::%s() cannot take arguments", scope->name, ptr->fname);
                                                            }
                                                        } else if ((fname_len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME) - 1)) {
                                                            clone = reg_function; // 函数名是"__clone"
                                                        } else if ((fname_len == sizeof(ZEND_CALL_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME) - 1)) {
                                                            __call = reg_function;
                                                        } else if ((fname_len == sizeof(ZEND_CALLSTATIC_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_CALLSTATIC_FUNC_NAME, sizeof(ZEND_CALLSTATIC_FUNC_NAME) - 1)) {
                                                            __callstatic = reg_function;
                                                        } else if ((fname_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME) - 1)) {
                                                            __tostring = reg_function;
                                                        } else if ((fname_len == sizeof(ZEND_GET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME) - 1)) {
                                                            __get = reg_function;
                                                        } else if ((fname_len == sizeof(ZEND_SET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME) - 1)) {
                                                            __set = reg_function;
                                                        } else if ((fname_len == sizeof(ZEND_UNSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_UNSET_FUNC_NAME, sizeof(ZEND_UNSET_FUNC_NAME) - 1)) {
                                                            __unset = reg_function;
                                                        } else if ((fname_len == sizeof(ZEND_ISSET_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_ISSET_FUNC_NAME, sizeof(ZEND_ISSET_FUNC_NAME) - 1)) {
                                                            __isset = reg_function;
                                                        } else if ((fname_len == sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && !memcmp(lowercase_name, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME) - 1)) {
                                                            __debugInfo = reg_function;
                                                        } else {
                                                            reg_function = NULL;
                                                        }
                                                        if (reg_function) {
                                                            zend_check_magic_method_implementation(scope, reg_function, error_type TSRMLS_CC);
                                                        }
                                                    }
                                                    ptr++;
                                                    count++;
                                                    str_efree(lowercase_name);
                                                }
                                                if (unload) { /* before unloading, display all remaining bad function in the module */
                                                    if (scope) {
                                                        efree((char*)lc_class_name);
                                                    }
                                                    while (ptr->fname) {
                                                        fname_len = strlen(ptr->fname);
                                                        lowercase_name = zend_str_tolower_dup(ptr->fname, fname_len);
                                                        if (zend_hash_exists(target_function_table, lowercase_name, fname_len+1)) {
                                                            zend_error(error_type, "Function registration failed - duplicate name - %s%s%s", scope ? scope->name : "", scope ? "::" : "", ptr->fname);
                                                        }
                                                        efree((char*)lowercase_name);
                                                        ptr++;
                                                    }
                                                    zend_unregister_functions(functions, count, target_function_table TSRMLS_CC);
                                                    return FAILURE;
                                                }
                                                if (scope) { // 有指定作用域
                                                    scope->constructor = ctor; // 构造函数
                                                    scope->destructor = dtor; // 析构函数
                                                    scope->clone = clone; // clone函数
                                                    scope->__call = __call; // __call函数
                                                    scope->__callstatic = __callstatic;
                                                    scope->__tostring = __tostring;
                                                    scope->__get = __get;
                                                    scope->__set = __set;
                                                    scope->__unset = __unset;
                                                    scope->__isset = __isset;
                                                    scope->__debugInfo = __debugInfo;
                                                    if (ctor) {
                                                        ctor->common.fn_flags |= ZEND_ACC_CTOR;
                                                        if (ctor->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Constructor %s::%s() cannot be static", scope->name, ctor->common.function_name);
                                                        }
                                                        ctor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (dtor) {
                                                        dtor->common.fn_flags |= ZEND_ACC_DTOR;
                                                        if (dtor->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Destructor %s::%s() cannot be static", scope->name, dtor->common.function_name);
                                                        }
                                                        dtor->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (clone) {
                                                        clone->common.fn_flags |= ZEND_ACC_CLONE;
                                                        if (clone->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Constructor %s::%s() cannot be static", scope->name, clone->common.function_name);
                                                        }
                                                        clone->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (__call) {
                                                        if (__call->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __call->common.function_name);
                                                        }
                                                        __call->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (__callstatic) {
                                                        if (!(__callstatic->common.fn_flags & ZEND_ACC_STATIC)) {
                                                            zend_error(error_type, "Method %s::%s() must be static", scope->name, __callstatic->common.function_name);
                                                        }
                                                        __callstatic->common.fn_flags |= ZEND_ACC_STATIC;
                                                    }
                                                    if (__tostring) {
                                                        if (__tostring->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __tostring->common.function_name);
                                                        }
                                                        __tostring->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (__get) {
                                                        if (__get->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __get->common.function_name);
                                                        }
                                                        __get->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (__set) {
                                                        if (__set->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __set->common.function_name);
                                                        }
                                                        __set->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (__unset) {
                                                        if (__unset->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __unset->common.function_name);
                                                        }
                                                        __unset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (__isset) {
                                                        if (__isset->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __isset->common.function_name);
                                                        }
                                                        __isset->common.fn_flags &= ~ZEND_ACC_ALLOW_STATIC;
                                                    }
                                                    if (__debugInfo) {
                                                        if (__debugInfo->common.fn_flags & ZEND_ACC_STATIC) {
                                                            zend_error(error_type, "Method %s::%s() cannot be static", scope->name, __debugInfo->common.function_name);
                                                        }
                                                    }
                                                    efree((char*)lc_class_name);
                                                }
                                                return SUCCESS;
                                            }
                                        }==FAILURE) { // 注册模块的函数到 CG(function_table)
                                            EG(current_module) = NULL;
                                            zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load", module->name);
                                            return NULL;
                                        }
                                    
                                        EG(current_module) = NULL;
                                        return module;
                                    }
                                
                                } == NULL) { // 把模块信息添加到模块注册表module_registry中 
                                    DL_UNLOAD(handle);
                                    return FAILURE;
                                }
                            
                                if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) {
                                    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) {
                                        php_error_docref(NULL TSRMLS_CC, error_type, "Unable to initialize module '%s'", module_entry->name);
                                        DL_UNLOAD(handle);
                                        return FAILURE;
                                    }
                                }
                                return SUCCESS;
                            }
                        }
                    }
                }
                ...
            }
            ...
        }
        ...
    }
    ...
}

 

posted on 2018-03-23 10:50  周~~  阅读(189)  评论(0编辑  收藏  举报

导航