I finally got a chance to test under Windows today, and there was a variable that was not being initialized under ZTS mode that was causing problems in Windows. The attached patch is correctly initializing it. Also, the namespace_anonymous.php file was missing from the patch, which the attached now has. The files used by the tests have not changed, so tests.tar.gz from the first post in this thread can still be used.
Regards, Jessie Jessie Hernandez wrote: > Classes that had uppercase letters were not being handled properly in > namespace imports. The attached patch has this fix (thanks Maxx!). Also, > the attached patch includes the default behavior of resolving > simple-imported class names to their file paths (ns:class1 being looked up > as ns/class1(.inc or .inc.php). > > I have a couple of questions, though: > > 1) I asked this before, but it wasn't answered: is there any reason why > .php is not a default extension for spl_autoload? > > 2) Right now, you have to use the autoload_import_class function for > namespace imports so that the class names are properly found. This > function can be eliminated if there was a way for me to get the last > inserted element in the class_table. Can I just simply call > zend_hash_internal_pointer_end_ex on class_table and get that end element, > assuming that this was the last element that was inserted? Or is the order > in which items are inserted into a hashtable undefined? > > > Regards, > > Jessie
Index: Zend/zend.c =================================================================== RCS file: /repository/ZendEngine2/zend.c,v retrieving revision 1.306 diff -u -r1.306 zend.c --- Zend/zend.c 27 Jun 2005 22:04:41 -0000 1.306 +++ Zend/zend.c 10 Aug 2005 02:55:49 -0000 @@ -34,10 +34,14 @@ # define GLOBAL_CLASS_TABLE global_class_table # define GLOBAL_CONSTANTS_TABLE global_constants_table # define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table +# define GLOBAL_IMPORT_CLASS_TABLE global_import_class_table +# define GLOBAL_IMPORT_NAMESPACE_TABLE global_import_namespace_table #else # define GLOBAL_FUNCTION_TABLE CG(function_table) # define GLOBAL_CLASS_TABLE CG(class_table) # define GLOBAL_AUTO_GLOBALS_TABLE CG(auto_globals) +# define GLOBAL_IMPORT_CLASS_TABLE CG(import_class_table) +# define GLOBAL_IMPORT_NAMESPACE_TABLE CG(import_namespace_table) #endif #if defined(ZEND_WIN32) && ZEND_DEBUG @@ -88,6 +92,8 @@ HashTable *global_class_table; HashTable *global_constants_table; HashTable *global_auto_globals_table; +HashTable *global_import_class_table; +HashTable *global_import_namespace_table; #endif ZEND_API zend_utility_values zend_uv; @@ -430,6 +436,7 @@ { zend_function tmp_func; zend_class_entry *tmp_class; + HashTable tmp_hash; compiler_globals->compiled_filename = NULL; @@ -443,6 +450,25 @@ zend_set_default_compile_time_values(TSRMLS_C); + /* initialize namespace variables */ + compiler_globals->in_anonymous_namespace = 0; + compiler_globals->namespace_prefix = NULL; + compiler_globals->namespace_prefix_lc = NULL; + compiler_globals->namespace_prefix_len = 0; + INIT_ZVAL(compiler_globals->extending_child); + + /* initialize the import class table */ + compiler_globals->import_class_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->current_import_class_table = NULL; + zend_hash_init_ex(compiler_globals->import_class_table, 10, NULL, (dtor_func_t) zend_hash_destroy, 1, 0); + zend_hash_copy(compiler_globals->import_class_table, global_import_class_table, NULL, &tmp_hash, sizeof(tmp_hash)); + + /* initialize the import namespace table */ + compiler_globals->import_namespace_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->current_import_namespace_table = NULL; + zend_hash_init_ex(compiler_globals->import_namespace_table, 10, NULL, (dtor_func_t) zend_hash_destroy, 1, 0); + zend_hash_copy(compiler_globals->import_namespace_table, global_import_namespace_table, NULL, &tmp_hash, sizeof(tmp_hash)); + CG(interactive) = 0; compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable)); @@ -465,6 +491,14 @@ zend_hash_destroy(compiler_globals->auto_globals); free(compiler_globals->auto_globals); } + if (compiler_globals->import_class_table != GLOBAL_IMPORT_CLASS_TABLE) { + zend_hash_destroy(compiler_globals->import_class_table); + free(compiler_globals->import_class_table); + } + if (compiler_globals->import_namespace_table != GLOBAL_IMPORT_NAMESPACE_TABLE) { + zend_hash_destroy(compiler_globals->import_namespace_table); + free(compiler_globals->import_namespace_table); + } } @@ -588,11 +622,15 @@ GLOBAL_FUNCTION_TABLE = (HashTable *) malloc(sizeof(HashTable)); GLOBAL_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_IMPORT_CLASS_TABLE = (HashTable *) malloc(sizeof(HashTable)); + GLOBAL_IMPORT_NAMESPACE_TABLE = (HashTable *) malloc(sizeof(HashTable)); #ifdef ZTS GLOBAL_CONSTANTS_TABLE = (HashTable *) malloc(sizeof(HashTable)); #endif zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0); zend_hash_init_ex(GLOBAL_CLASS_TABLE, 10, NULL, ZEND_CLASS_DTOR, 1, 0); + zend_hash_init_ex(GLOBAL_IMPORT_CLASS_TABLE, 10, NULL, (dtor_func_t) zend_hash_destroy, 1, 0); + zend_hash_init_ex(GLOBAL_IMPORT_NAMESPACE_TABLE, 10, NULL, (dtor_func_t) zend_hash_destroy, 1, 0); zend_hash_init_ex(&module_registry, 50, NULL, ZEND_MODULE_DTOR, 1, 0); zend_init_rsrc_list_dtors(); @@ -618,10 +656,18 @@ compiler_globals->in_compilation = 0; compiler_globals->function_table = (HashTable *) malloc(sizeof(HashTable)); compiler_globals->class_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->import_class_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->import_namespace_table = (HashTable *) malloc(sizeof(HashTable)); + compiler_globals->in_anonymous_namespace = 0; + compiler_globals->current_import_class_table = NULL; + compiler_globals->current_import_namespace_table = NULL; + INIT_ZVAL(compiler_globals->extending_child); *compiler_globals->function_table = *GLOBAL_FUNCTION_TABLE; *compiler_globals->class_table = *GLOBAL_CLASS_TABLE; compiler_globals->auto_globals = GLOBAL_AUTO_GLOBALS_TABLE; + *compiler_globals->import_class_table = *GLOBAL_IMPORT_CLASS_TABLE; + *compiler_globals->import_namespace_table = *GLOBAL_IMPORT_NAMESPACE_TABLE; zend_hash_destroy(executor_globals->zend_constants); *executor_globals->zend_constants = *GLOBAL_CONSTANTS_TABLE; @@ -676,9 +722,13 @@ *GLOBAL_FUNCTION_TABLE = *compiler_globals->function_table; *GLOBAL_CLASS_TABLE = *compiler_globals->class_table; *GLOBAL_CONSTANTS_TABLE = *executor_globals->zend_constants; + *GLOBAL_IMPORT_CLASS_TABLE = *compiler_globals->import_class_table; + *GLOBAL_IMPORT_NAMESPACE_TABLE = *compiler_globals->import_namespace_table; zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); free(compiler_globals->function_table); free(compiler_globals->class_table); + free(compiler_globals->import_class_table); + free(compiler_globals->import_namespace_table); compiler_globals_ctor(compiler_globals, tsrm_ls); free(EG(zend_constants)); executor_globals_ctor(executor_globals, tsrm_ls); @@ -699,6 +749,8 @@ zend_hash_destroy(GLOBAL_FUNCTION_TABLE); zend_hash_destroy(GLOBAL_CLASS_TABLE); + zend_hash_destroy(GLOBAL_IMPORT_CLASS_TABLE); + zend_hash_destroy(GLOBAL_IMPORT_NAMESPACE_TABLE); zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE); free(GLOBAL_AUTO_GLOBALS_TABLE); @@ -709,6 +761,8 @@ zend_shutdown_constants(TSRMLS_C); free(GLOBAL_FUNCTION_TABLE); free(GLOBAL_CLASS_TABLE); + free(GLOBAL_IMPORT_CLASS_TABLE); + free(GLOBAL_IMPORT_NAMESPACE_TABLE); #ifdef ZTS zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); zend_hash_destroy(GLOBAL_CONSTANTS_TABLE); @@ -716,6 +770,8 @@ GLOBAL_FUNCTION_TABLE = NULL; GLOBAL_CLASS_TABLE = NULL; GLOBAL_AUTO_GLOBALS_TABLE = NULL; + GLOBAL_IMPORT_CLASS_TABLE = NULL; + GLOBAL_IMPORT_NAMESPACE_TABLE = NULL; #endif zend_destroy_rsrc_list_dtors(); } Index: Zend/zend_builtin_functions.c =================================================================== RCS file: /repository/ZendEngine2/zend_builtin_functions.c,v retrieving revision 1.276 diff -u -r1.276 zend_builtin_functions.c --- Zend/zend_builtin_functions.c 27 Jun 2005 18:13:13 -0000 1.276 +++ Zend/zend_builtin_functions.c 10 Aug 2005 02:55:50 -0000 @@ -76,6 +76,8 @@ static ZEND_FUNCTION(get_defined_constants); static ZEND_FUNCTION(debug_backtrace); static ZEND_FUNCTION(debug_print_backtrace); +static ZEND_FUNCTION(get_imported_namespaces); +static ZEND_FUNCTION(autoload_import_class); #if ZEND_DEBUG static ZEND_FUNCTION(zend_test_func); #ifdef ZTS @@ -138,6 +140,8 @@ ZEND_FE(get_defined_constants, NULL) ZEND_FE(debug_backtrace, NULL) ZEND_FE(debug_print_backtrace, NULL) + ZEND_FE(get_imported_namespaces, NULL) + ZEND_FE(autoload_import_class, NULL) #if ZEND_DEBUG ZEND_FE(zend_test_func, NULL) #ifdef ZTS @@ -1996,6 +2000,113 @@ } /* }}} */ +static int copy_namespace_name(zval *name, void *return_array) +{ + add_next_index_stringl((zval *) return_array, Z_STRVAL_P(name), Z_STRLEN_P(name), 1); + return ZEND_HASH_APPLY_KEEP; +} + +/* {{{ proto array get_imported_namespaces([$className]) + Returns an array of all imported namespaces. */ +ZEND_FUNCTION(get_imported_namespaces) +{ + char *class_name = NULL; + char *class_name_lc = NULL; + int class_name_len = 0; + HashTable *import_table = NULL; + zval *referencing_file = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &class_name, &class_name_len) == FAILURE) { + return; + } + + if (class_name != NULL) { + /* lowercase the class name */ + class_name_lc = zend_str_tolower_dup(class_name, class_name_len); + + if (zend_hash_find(&EG(autoload_class_file_map), class_name_lc, class_name_len + 1, (void **) &referencing_file) == SUCCESS) { + zend_hash_find(EG(import_namespace_table), Z_STRVAL_P(referencing_file), Z_STRLEN_P(referencing_file) + 1, (void **) &import_table); + } + + efree(class_name_lc); + } else { + zend_hash_find(EG(import_namespace_table), zend_get_executed_filename(TSRMLS_C), strlen(zend_get_executed_filename(TSRMLS_C)) + 1, (void **) &import_table); + } + + array_init(return_value); + + if (import_table != NULL) { + zend_hash_apply_with_argument(import_table, (apply_func_arg_t) copy_namespace_name, return_value TSRMLS_CC); + } +} +/* }}} */ + +/* {{{ proto boolean autoload_import_class($className, $namespaceName) + Registers a class with its namespace that has been fully imported (can only be used while in an __autoload operation). */ +ZEND_FUNCTION(autoload_import_class) +{ + char *class_name = NULL; + int class_name_len = 0; + char *class_name_lc = NULL; + HashTable *current_import_table = NULL; + char *full_name = NULL; + int full_name_len = 0; + zval import_val; + char *namespace_name = NULL; + int namespace_name_len = 0; + zval *referencing_file = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &class_name, &class_name_len, &namespace_name, &namespace_name_len) == FAILURE) { + RETURN_FALSE; + } + + /* get lowercased class name */ + class_name_lc = zend_str_tolower_dup(class_name, class_name_len); + + if (zend_hash_exists(EG(in_autoload), class_name_lc, class_name_len + 1)) { + /* get the referencing file name */ + zend_hash_find(&EG(autoload_class_file_map), class_name_lc, class_name_len + 1, (void **) &referencing_file); + + if (zend_hash_find(EG(import_class_table), Z_STRVAL_P(referencing_file), Z_STRLEN_P(referencing_file) + 1, (void **)¤t_import_table) == SUCCESS) { + /* make sure this import alias has not been used before */ + if (zend_hash_exists(current_import_table, class_name_lc, class_name_len + 1)) { + zend_error(E_ERROR, "An import was already done with the %s alias", class_name); + efree(class_name_lc); + RETURN_FALSE; + } + + /* get the full class name */ + full_name_len = namespace_name_len + class_name_len + 1; + full_name = malloc(full_name_len + 1); + strncpy(full_name, namespace_name, namespace_name_len + 1); + strcat(full_name, ":"); + strcat(full_name, class_name); + + /* initialize the full class name zval */ + INIT_ZVAL(import_val); + Z_STRVAL(import_val) = full_name; + Z_STRLEN(import_val) = full_name_len; + + /* add the import alias */ + if (zend_hash_add(current_import_table, class_name_lc, class_name_len + 1, &import_val, sizeof(import_val), NULL) == FAILURE) { + zend_error(E_ERROR, "Could not import %s", class_name); + efree(class_name_lc); + RETURN_FALSE; + } + + efree(class_name_lc); + RETURN_TRUE; + } + } else { + zend_error(E_ERROR, "Class %s is not being autoloaded", class_name); + RETURN_FALSE; + } + + efree(class_name_lc); + RETURN_FALSE; +} +/* }}} */ + /* {{{ proto bool extension_loaded(string extension_name) Returns true if the named extension is loaded */ ZEND_FUNCTION(extension_loaded) Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.644 diff -u -r1.644 zend_compile.c --- Zend/zend_compile.c 17 Jul 2005 19:17:10 -0000 1.644 +++ Zend/zend_compile.c 10 Aug 2005 02:55:51 -0000 @@ -182,11 +182,34 @@ } +void import_zval_dtor(zval *zv) +{ + free(Z_STRVAL_P(zv)); +} + ZEND_API char *zend_set_compiled_filename(char *new_compiled_filename TSRMLS_DC) { char **pp, *p; + HashTable file_class_imports; + HashTable file_namespace_imports; int length = strlen(new_compiled_filename); + /* make sure the import class hashtable for this file exists */ + if (!zend_hash_exists(CG(import_class_table), new_compiled_filename, length+1)) { + zend_hash_init(&file_class_imports, 10, NULL, (dtor_func_t) import_zval_dtor, 1); + zend_hash_add(CG(import_class_table), new_compiled_filename, length + 1, &file_class_imports, sizeof(file_class_imports), NULL); + } + + /* make sure the import namespace hashtable for this file exists */ + if (!zend_hash_exists(CG(import_namespace_table), new_compiled_filename, length+1)) { + zend_hash_init(&file_namespace_imports, 10, NULL, (dtor_func_t) import_zval_dtor, 1); + zend_hash_add(CG(import_namespace_table), new_compiled_filename, length + 1, &file_namespace_imports, sizeof(file_namespace_imports), NULL); + } + + /* get the import hashtables for this file */ + zend_hash_find(CG(import_class_table), new_compiled_filename, length + 1, (void **)&CG(current_import_class_table)); + zend_hash_find(CG(import_namespace_table), new_compiled_filename, length + 1, (void **)&CG(current_import_namespace_table)); + if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp) == SUCCESS) { CG(compiled_filename) = *pp; return *pp; @@ -1374,7 +1397,18 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_CLASS; - SET_UNUSED(opline->op1); + + if (CG(extending_child).type == IS_NULL) { + SET_UNUSED(opline->op1); + } else { + /* copy the child name */ + INIT_ZVAL(opline->op1.u.constant); + opline->op1.op_type = IS_CONST; + opline->op1.u.constant.type = IS_STRING; + opline->op1.u.constant.value.str.val = estrndup(CG(extending_child).value.str.val, CG(extending_child).value.str.len); + opline->op1.u.constant.value.str.len = CG(extending_child).value.str.len; + } + opline->extended_value = ZEND_FETCH_CLASS_GLOBAL; CG(catch_begin) = fetch_class_op_number; if (class_name->op_type == IS_CONST) { @@ -2626,6 +2660,11 @@ zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val); } + /* fully prefix the class name */ + efree(lcname); + zend_prefix_class_name_node(class_name TSRMLS_CC); + lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len); + new_class_entry->type = ZEND_USER_CLASS; new_class_entry->name = class_name->u.constant.value.str.val; new_class_entry->name_length = class_name->u.constant.value.str.len; @@ -2674,6 +2713,11 @@ opline->result.op_type = IS_CONST; CG(implementing_class) = opline->result; + /* if we are in an anonymous namespace, then immediately import this class */ + if (CG(in_anonymous_namespace)) { + zend_do_import(NULL, class_name, NULL TSRMLS_CC); + } + if (CG(doc_comment)) { CG(active_class_entry)->doc_comment = CG(doc_comment); CG(active_class_entry)->doc_comment_len = CG(doc_comment_len); @@ -2682,6 +2726,188 @@ } } +/***************************** + * BEGIN NAMESPACE FUNCTIONS * + *****************************/ + +void zend_do_begin_extending(znode *child_name TSRMLS_DC) +{ + int name_len = Z_STRLEN(child_name->u.constant); + + /* add the namespace prefix length, if applicable */ + if (CG(namespace_prefix) != NULL) { + name_len += CG(namespace_prefix_len); + } + + INIT_ZVAL(CG(extending_child)); + CG(extending_child).type = IS_STRING; + Z_STRVAL(CG(extending_child)) = emalloc(name_len + 1); + Z_STRLEN(CG(extending_child)) = name_len; + + if (CG(namespace_prefix) != NULL) { + /* copy the namespace prefix, then the child name */ + strncpy(Z_STRVAL(CG(extending_child)), CG(namespace_prefix), CG(namespace_prefix_len) + 1); + strcat(Z_STRVAL(CG(extending_child)), Z_STRVAL(child_name->u.constant)); + } else { + /* copy just the class name */ + strncpy(Z_STRVAL(CG(extending_child)), Z_STRVAL(child_name->u.constant), Z_STRLEN(child_name->u.constant) + 1); + } +} + +void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC) +{ + char *namespace_name = NULL; + int namespace_name_len = 0; + + if (ns_name != NULL) { + namespace_name = Z_STRVAL(ns_name->u.constant); + namespace_name_len = Z_STRLEN(ns_name->u.constant); + } else { + /* this is an anonymous namespace */ + CG(in_anonymous_namespace) = 1; + namespace_name = zend_get_compiled_filename(TSRMLS_C); + namespace_name_len = strlen(namespace_name); + } + + /* allocate space for the namespace prefix */ + CG(namespace_prefix) = emalloc(namespace_name_len + 2); + + /* get the namespace prefix */ + strncpy(CG(namespace_prefix), namespace_name, namespace_name_len + 1); + strcat(CG(namespace_prefix), ":"); + + /* get the lowercased namespace prefix */ + CG(namespace_prefix_lc) = zend_str_tolower_dup(CG(namespace_prefix), namespace_name_len + 1); + + /* save the prefix length */ + CG(namespace_prefix_len) = namespace_name_len + 1; + + /* we don't need the namespace name anymore, so free it */ + if (ns_name != NULL) { + zval_dtor(&ns_name->u.constant); + } +} + +void zend_do_end_extending(TSRMLS_D) +{ + efree(Z_STRVAL(CG(extending_child))); + CG(extending_child).type = IS_NULL; + Z_STRLEN(CG(extending_child)) = 0; + Z_STRVAL(CG(extending_child)) = NULL; +} + +void zend_do_end_namespace(znode *ns_token TSRMLS_DC) +{ + /* free the string memory */ + efree(CG(namespace_prefix)); + efree(CG(namespace_prefix_lc)); + CG(namespace_prefix_len) = 0; + + /* set the prefixes to null */ + CG(namespace_prefix) = NULL; + CG(namespace_prefix_lc) = NULL; + + CG(in_anonymous_namespace) = 0; +} + +void zend_do_verify_private_class(TSRMLS_D) +{ + if (CG(namespace_prefix) == NULL) { + zend_error(E_COMPILE_ERROR, "Cannot declare a private class in the global namespace"); + } +} + +void zend_do_import(znode *result, znode *class_name, znode *alias_name TSRMLS_DC) +{ + char *alias_name_lc = NULL; + zend_uint alias_name_len = 0; + zval alias_val; + /* 'colon_pos' is the position of the last colon in the full class name */ + char *colon_pos = strrchr(Z_STRVAL(class_name->u.constant), ':'); + /* 'last_pos' is the position of the null terminator in the full class name */ + char *last_pos = Z_STRVAL(class_name->u.constant) + Z_STRLEN(class_name->u.constant); + + if (colon_pos == NULL) { + zend_error(E_COMPILE_ERROR, "Cannot import non-namespace class: %s!", Z_STRVAL(class_name->u.constant)); + return; + } + + if (alias_name == NULL) { + /* advance to the first character of the class name */ + ++colon_pos; + + /* get the lowercased class name as the alias */ + alias_name_len = last_pos - colon_pos; + alias_name_lc = zend_str_tolower_dup(colon_pos, alias_name_len); + } else /* alias_name != NULL */ { + alias_name_lc = zend_str_tolower_dup(Z_STRVAL(alias_name->u.constant), Z_STRLEN(alias_name->u.constant)); + alias_name_len = Z_STRLEN(alias_name->u.constant); + zval_dtor(&alias_name->u.constant); + } + + /* make sure this import alias has not been used before */ + if (zend_hash_exists(CG(current_import_class_table), alias_name_lc, alias_name_len + 1)) { + zend_error(E_COMPILE_ERROR, "An import was already done with the %s alias", alias_name_lc); + return; + } + + /* create the alias value */ + INIT_ZVAL(alias_val); + Z_STRVAL(alias_val) = zend_strndup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); + Z_STRLEN(alias_val) = Z_STRLEN(class_name->u.constant); + + /* add the alias */ + if (zend_hash_add(CG(current_import_class_table), alias_name_lc, alias_name_len + 1, &alias_val, sizeof(zval), NULL) == FAILURE) { + zend_error(E_COMPILE_ERROR, "Could not import %s as %s!", Z_STRVAL(class_name->u.constant), alias_name_lc); + } + + zval_dtor(&class_name->u.constant); + efree(alias_name_lc); +} + +void zend_do_namespace_import(znode *ns_name TSRMLS_DC) +{ + zval name_val; + + INIT_ZVAL(name_val); + name_val.type = IS_STRING; + Z_STRVAL(name_val) = zend_strndup(Z_STRVAL(ns_name->u.constant), Z_STRLEN(ns_name->u.constant)); + Z_STRLEN(name_val) = Z_STRLEN(ns_name->u.constant); + + /* we don't need the namespace name anymore, so free it */ + zval_dtor(&ns_name->u.constant); + + if (zend_hash_next_index_insert(CG(current_import_namespace_table), &name_val, sizeof(name_val), NULL) == FAILURE) { + zend_error(E_COMPILE_ERROR, "Could not import namespace %s!", Z_STRVAL(ns_name->u.constant)); + return; + } +} + +void zend_prefix_class_name_node(znode *class_name TSRMLS_DC) +{ + zend_uint new_length = 0; + char *org_class_name = NULL; + + if (CG(namespace_prefix) != NULL) { + new_length = CG(namespace_prefix_len) + Z_STRLEN(class_name->u.constant); + org_class_name = estrdup(Z_STRVAL(class_name->u.constant)); + + STR_REALLOC(Z_STRVAL(class_name->u.constant), new_length + 1); + + /* get the full class name */ + strncpy(Z_STRVAL(class_name->u.constant), CG(namespace_prefix), CG(namespace_prefix_len) + 1); + strcat(Z_STRVAL(class_name->u.constant), org_class_name); + + /* get the new string length */ + Z_STRLEN(class_name->u.constant) = new_length; + + efree(org_class_name); + } +} + +/*************************** + * END NAMESPACE FUNCTIONS * + ***************************/ static void do_verify_abstract_class(TSRMLS_D) { Index: Zend/zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.315 diff -u -r1.315 zend_compile.h --- Zend/zend_compile.h 7 Jul 2005 16:07:09 -0000 1.315 +++ Zend/zend_compile.h 10 Aug 2005 02:55:51 -0000 @@ -387,6 +387,7 @@ void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC); int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier); +void zend_do_verify_private_class(TSRMLS_D); void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); void zend_do_end_function_declaration(znode *function_token TSRMLS_DC); void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, znode *varname, zend_bool pass_by_reference TSRMLS_DC); @@ -438,6 +439,15 @@ void zend_do_declare_implicit_property(TSRMLS_D); void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC); +void zend_do_begin_extending(znode *child_name TSRMLS_DC); +void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC); +void zend_do_end_extending(TSRMLS_D); +void zend_do_end_namespace(znode *ns_token TSRMLS_DC); +void zend_do_import(znode *result, znode *class_name, znode *alias_name TSRMLS_DC); +void zend_do_namespace_import(znode *ns_name TSRMLS_DC); +void zend_do_unimport_all(TSRMLS_D); +void zend_prefix_class_name_node(znode *class_name TSRMLS_DC); + void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC); Index: Zend/zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.327 diff -u -r1.327 zend_execute_API.c --- Zend/zend_execute_API.c 12 Jul 2005 06:52:59 -0000 1.327 +++ Zend/zend_execute_API.c 10 Aug 2005 02:55:52 -0000 @@ -135,6 +135,8 @@ EG(function_table) = CG(function_table); EG(class_table) = CG(class_table); + EG(import_class_table) = CG(import_class_table); + EG(import_namespace_table) = CG(import_namespace_table); EG(in_execution) = 0; EG(in_autoload) = NULL; @@ -156,6 +158,8 @@ } EG(active_symbol_table) = &EG(symbol_table); + zend_hash_init(&EG(autoload_class_file_map), 1, NULL, ZVAL_PTR_DTOR, 0); + zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator TSRMLS_CC); EG(opline_ptr) = NULL; @@ -292,6 +296,8 @@ zend_hash_destroy(EG(in_autoload)); FREE_HASHTABLE(EG(in_autoload)); } + + zend_hash_destroy(&EG(autoload_class_file_map)); } zend_end_try(); } @@ -906,6 +912,112 @@ } +char* zend_get_class_namespace(const char *class_name) +{ + int namespace_length = 0; + char *result = NULL; + char *tmp = strrchr(class_name, ':'); + + if (tmp != NULL) { + namespace_length = tmp - class_name; + + /* get the namespace name, which is everything before the last colon */ + result = estrndup(class_name, namespace_length); + zend_str_tolower(result, namespace_length); + } + + return result; +} + + +zval *zend_resolve_class_name_string(char *name, int name_len TSRMLS_DC) +{ + HashTable *current_import_table = NULL; + char *executed_filename = zend_get_executed_filename(TSRMLS_C); + int executed_filename_len = strlen(executed_filename); + char *lc_name = NULL; + zval* mapped_class_name = NULL; + + if (zend_hash_find(EG(import_class_table), executed_filename, executed_filename_len + 1, (void **)¤t_import_table) == SUCCESS) { + /* get the lowercased class name */ + lc_name = zend_str_tolower_dup(name, name_len); + + /* check to see if this class name is actually an import alias */ + zend_hash_find(current_import_table, lc_name, name_len + 1, (void **)&mapped_class_name); + + /* free the class name string */ + efree(lc_name); + } + + return mapped_class_name; +} + + +int zend_verify_can_use_class(zend_class_entry *ce TSRMLS_DC) +{ + int result = SUCCESS; + + /* exit immediately if this is not a private class */ + if ((ce->ce_flags & ZEND_ACC_PRIVATE) == 0) { + return SUCCESS; + } + + /* check if we are in compilation mode */ + if (zend_is_compiling(TSRMLS_C)) { + char *class_namespace = zend_get_class_namespace(ce->name); + char *current_namespace = NULL; + + if (CG(namespace_prefix) != NULL) { + /* copy the namespace prefix minus the last character, which is a colon */ + current_namespace = estrndup(CG(namespace_prefix), CG(namespace_prefix_len) - 1); + } + + /* check if the namespaces match */ + if (class_namespace != NULL + && (current_namespace == NULL + || strcmp(class_namespace, current_namespace) != 0)) { + /* the namespaces don't match, so don't allow use of this class */ + result = FAILURE; + } + + efree(class_namespace); + efree(current_namespace); + } else /* zend_is_executing */ { + char *class_namespace = zend_get_class_namespace(ce->name); + char *current_namespace = NULL; + + if (active_opline->opcode == ZEND_FETCH_CLASS && active_opline->op1.op_type == IS_CONST) { + current_namespace = zend_get_class_namespace(active_opline->op1.u.constant.value.str.val); + } else if (EG(scope) != NULL) { + current_namespace = zend_get_class_namespace(EG(scope)->name); + } + + /* check if the namespaces match */ + if (class_namespace != NULL + && (current_namespace == NULL + || strcmp(class_namespace, current_namespace) != 0)) { + /* the namespaces don't match, so don't allow use of this class */ + result = FAILURE; + } + + if (class_namespace != NULL) { + efree(class_namespace); + } + + if (current_namespace != NULL) { + efree(current_namespace); + } + } + + /* generate the error message, if needed */ + if (result == FAILURE) { + zend_error(E_ERROR, "Cannot use class '%s' outside of its namespace, as it is private", ce->name); + } + + return result; +} + + ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) { zval **args[1]; @@ -918,17 +1030,38 @@ char dummy = 1; zend_fcall_info fcall_info; zend_fcall_info_cache fcall_cache; + zval executed_filename_val; + zval *resolved_name = NULL; if (name == NULL) { return FAILURE; } - + lc_name = do_alloca(name_length + 1); zend_str_tolower_copy(lc_name, name, name_length); if (zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce) == SUCCESS) { free_alloca(lc_name); - return SUCCESS; + return zend_verify_can_use_class(**ce TSRMLS_CC); + } + + /* try to resolve the class name and try again */ + if ((resolved_name = zend_resolve_class_name_string(name, name_length TSRMLS_CC)) != NULL) { + /* get the new name */ + name = estrndup(Z_STRVAL_P(resolved_name), Z_STRLEN_P(resolved_name)); + name_length = Z_STRLEN_P(resolved_name); + + /* get the lowercased version of the resolved name */ + free_alloca(lc_name); + lc_name = do_alloca(name_length + 1); + zend_str_tolower_copy(lc_name, name, name_length); + + /* try the search with the resolved name */ + if (zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce) == SUCCESS) { + free_alloca(lc_name); + efree(name); + return zend_verify_can_use_class(**ce TSRMLS_CC); + } } /* The compiler is not-reentrant. Make sure we __autoload() only during run-time @@ -936,6 +1069,11 @@ */ if (zend_is_compiling(TSRMLS_C)) { free_alloca(lc_name); + + if (resolved_name != NULL) { + efree(name); + } + return FAILURE; } @@ -946,9 +1084,19 @@ if (zend_hash_add(EG(in_autoload), lc_name, name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) { free_alloca(lc_name); + + if (resolved_name != NULL) { + efree(name); + } + return FAILURE; } + /* insert the autoload class -> file mapping */ + INIT_ZVAL(executed_filename_val); + ZVAL_STRINGL(&executed_filename_val, zend_get_executed_filename(TSRMLS_C), strlen(zend_get_executed_filename(TSRMLS_C)), 1); + zend_hash_add(&EG(autoload_class_file_map), lc_name, name_length + 1, &executed_filename_val, sizeof(executed_filename_val), NULL); + ZVAL_STRINGL(&autoload_function, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1, 0); ALLOC_ZVAL(class_name_ptr); @@ -979,16 +1127,30 @@ zval_ptr_dtor(&class_name_ptr); + /* remove the autoload class -> file mapping */ + zend_hash_del(&EG(autoload_class_file_map), name, name_length + 1); + zval_dtor(&executed_filename_val); + zend_hash_del(EG(in_autoload), lc_name, name_length+1); if (retval == FAILURE) { EG(exception) = exception; free_alloca(lc_name); + + if (resolved_name != NULL) { + efree(name); + } + return FAILURE; } if (EG(exception) && exception) { free_alloca(lc_name); + + if (resolved_name != NULL) { + efree(name); + } + zend_error(E_ERROR, "Function %s(%s) threw an exception of type '%s'", ZEND_AUTOLOAD_FUNC_NAME, name, Z_OBJCE_P(EG(exception))->name); return FAILURE; } @@ -998,7 +1160,32 @@ } retval = zend_hash_find(EG(class_table), lc_name, name_length + 1, (void **) ce); + + /* try to resolve the class name after the autoload and try again */ + if (retval == FAILURE && (resolved_name = zend_resolve_class_name_string(name, name_length TSRMLS_CC)) != NULL) { + /* get the new name */ + name = estrndup(Z_STRVAL_P(resolved_name), Z_STRLEN_P(resolved_name)); + name_length = Z_STRLEN_P(resolved_name); + + /* get the lowercased version of the resolved name */ + free_alloca(lc_name); + lc_name = do_alloca(name_length + 1); + zend_str_tolower_copy(lc_name, name, name_length); + + /* try the search with the resolved name */ + retval = zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce); + } + free_alloca(lc_name); + + if (resolved_name != NULL) { + efree(name); + } + + if (retval == SUCCESS) { + retval = zend_verify_can_use_class(**ce TSRMLS_CC); + } + return retval; } Index: Zend/zend_globals.h =================================================================== RCS file: /repository/ZendEngine2/zend_globals.h,v retrieving revision 1.140 diff -u -r1.140 zend_globals.h --- Zend/zend_globals.h 3 Nov 2004 23:13:32 -0000 1.140 +++ Zend/zend_globals.h 10 Aug 2005 02:55:52 -0000 @@ -143,6 +143,17 @@ zend_encoding_converter encoding_converter; zend_encoding_oddlen encoding_oddlen; #endif /* ZEND_MULTIBYTE */ + + /* namespace-related variables */ + zend_bool in_anonymous_namespace; + char *namespace_prefix; + char *namespace_prefix_lc; + zend_uint namespace_prefix_len; + HashTable *import_class_table; + HashTable *import_namespace_table; + HashTable *current_import_class_table; + HashTable *current_import_namespace_table; + zval extending_child; }; @@ -232,6 +243,10 @@ zend_property_info std_property_info; + HashTable autoload_class_file_map; + HashTable *import_class_table; + HashTable *import_namespace_table; + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.159 diff -u -r1.159 zend_language_parser.y --- Zend/zend_language_parser.y 4 Jul 2005 13:24:44 -0000 1.159 +++ Zend/zend_language_parser.y 10 Aug 2005 02:55:52 -0000 @@ -145,7 +145,10 @@ %token T_DOLLAR_OPEN_CURLY_BRACES %token T_CURLY_OPEN %token T_PAAMAYIM_NEKUDOTAYIM - +%token T_IMPORT +%token T_NAMESPACE_NAME +%token T_NAMESPACE +%token T_NAMESPACE_C %% /* Rules */ start: @@ -162,6 +165,7 @@ statement | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } | class_declaration_statement { zend_do_early_binding(TSRMLS_C); } + | namespace_declaration_statement | T_HALT_COMPILER '(' ')' ';' { REGISTER_MAIN_LONG_CONSTANT("__COMPILER_HALT_OFFSET__", zend_get_scanned_file_offset(TSRMLS_C), CONST_CS); YYACCEPT; } ; @@ -231,6 +235,8 @@ '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); } | T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE_NAME ';' { zend_do_import(&$$, &$2, NULL TSRMLS_CC); } + | T_IMPORT T_NAMESPACE_NAME T_AS T_STRING ';' { zend_do_import(&$$, &$2, &$4 TSRMLS_CC); } ; @@ -286,8 +292,8 @@ ; unticked_class_declaration_statement: - class_entry_type T_STRING extends_from - { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } + class_entry_type T_STRING { zend_do_begin_extending(&$2 TSRMLS_CC); } extends_from { zend_do_end_extending(TSRMLS_C); } + { zend_do_begin_class_declaration(&$1, &$2, &$4 TSRMLS_CC); } implements_list '{' class_statement_list @@ -305,6 +311,23 @@ T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = 0; } | T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } | T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_FINAL_CLASS; } + | T_PRIVATE T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE; } + | T_PRIVATE T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } + | T_PRIVATE T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE | ZEND_ACC_FINAL_CLASS; } +; + +namespace_declaration_statement: + T_NAMESPACE '{' { zend_do_begin_namespace(&$1, NULL TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$1 TSRMLS_CC); } + | T_NAMESPACE namespace_name '{' { zend_do_begin_namespace(&$1, &$2 TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$1 TSRMLS_CC); } +; + +namespace_statement_list: + namespace_statement_list namespace_statement + | /* empty */ +; + +namespace_statement: + class_declaration_statement { zend_do_early_binding(TSRMLS_C); } ; extends_from: @@ -439,6 +462,7 @@ optional_class_type: /* empty */ { $$.op_type = IS_UNUSED; } | T_STRING { $$ = $1; } + | T_NAMESPACE_NAME { $$ = $1; } | T_ARRAY { $$.op_type = IS_CONST; $$.u.constant.type=IS_NULL;} ; @@ -639,10 +663,12 @@ fully_qualified_class_name: T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | T_NAMESPACE_NAME { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; class_name_reference: T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | T_NAMESPACE_NAME { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } | dynamic_class_name_reference { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; @@ -654,6 +680,10 @@ | base_variable { $$ = $1; } ; +namespace_name: + T_NAMESPACE_NAME { $$ = $1; } + | T_STRING { $$ = $1; } +; dynamic_class_name_variable_properties: dynamic_class_name_variable_properties dynamic_class_name_variable_property @@ -687,6 +717,7 @@ | T_CLASS_C { $$ = $1; } | T_METHOD_C { $$ = $1; } | T_FUNC_C { $$ = $1; } + | T_NAMESPACE_C { $$ = $1; } ; @@ -910,6 +941,8 @@ | T_EVAL '(' expr ')' { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); } | T_REQUIRE expr { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); } | T_REQUIRE_ONCE expr { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE T_NAMESPACE_NAME { zend_do_namespace_import(&$3 TSRMLS_CC); } + | T_IMPORT T_NAMESPACE T_STRING { zend_do_namespace_import(&$3 TSRMLS_CC); } ; isset_variables: Index: Zend/zend_language_scanner.l =================================================================== RCS file: /repository/ZendEngine2/zend_language_scanner.l,v retrieving revision 1.129 diff -u -r1.129 zend_language_scanner.l --- Zend/zend_language_scanner.l 16 Jun 2005 13:31:21 -0000 1.129 +++ Zend/zend_language_scanner.l 10 Aug 2005 02:55:52 -0000 @@ -790,6 +790,7 @@ ESCAPED_AND_WHITESPACE [\n\t\r #'.:;,()|^&+-/*=%!~<>[EMAIL PROTECTED] ANY_CHAR (.|[\n]) NEWLINE ("\r"|"\n"|"\r\n") +NAMESPACE_NAME ({LABEL}":")*{LABEL} %option noyylineno %option noyywrap @@ -923,6 +924,14 @@ return T_CLASS; } +<ST_IN_SCRIPTING>"namespace" { + return T_NAMESPACE; +} + +<ST_IN_SCRIPTING>"import" { + return T_IMPORT; +} + <ST_IN_SCRIPTING>"interface" { return T_INTERFACE; } @@ -1301,6 +1310,25 @@ return T_FUNC_C; } +<ST_IN_SCRIPTING>"__NAMESPACE__" { + char *namespace_name = NULL; + int namespace_name_len = 0; + + if (CG(namespace_prefix)) { + namespace_name = CG(namespace_prefix); + namespace_name_len = CG(namespace_prefix_len); + } + + if (!namespace_name) { + namespace_name = ":"; + namespace_name_len = 1; + } + zendlval->value.str.len = namespace_name_len - 1; + zendlval->value.str.val = estrndup(namespace_name, zendlval->value.str.len); + zendlval->type = IS_STRING; + return T_NAMESPACE_C; +} + <ST_IN_SCRIPTING>"__METHOD__" { char *class_name = CG(active_class_entry) ? CG(active_class_entry)->name : NULL; char *func_name = CG(active_op_array)? CG(active_op_array)->function_name : NULL; @@ -1433,6 +1461,13 @@ return T_STRING; } +<ST_IN_SCRIPTING>{NAMESPACE_NAME} { + zendlval->value.str.val = (char *)estrndup(yytext, yyleng); + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + return T_NAMESPACE_NAME; +} + <ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>{LABEL} { zend_copy_value(zendlval, yytext, yyleng); zendlval->type = IS_STRING; Index: ext/spl/php_spl.c =================================================================== RCS file: /repository/php-src/ext/spl/php_spl.c,v retrieving revision 1.49 diff -u -r1.49 php_spl.c --- ext/spl/php_spl.c 17 Jun 2005 16:42:53 -0000 1.49 +++ ext/spl/php_spl.c 10 Aug 2005 02:56:00 -0000 @@ -203,7 +203,21 @@ zend_op_array *new_op_array; zval *result = NULL; - class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension); + /* if the class name contains one or more colons, then replace these with + the directory separators */ + if (strchr(lc_name, ':') != NULL) { + char *lc_name_cpy = estrndup(lc_name, class_name_len); + char *lc_name_bak = lc_name_cpy; + + while((lc_name_bak = strchr(lc_name_bak, ':')) != NULL) { + *lc_name_bak++ = DEFAULT_SLASH; + } + + class_file_len = spprintf(&class_file, 0, "%s%s", lc_name_cpy, file_extension); + efree(lc_name_cpy); + } else { + class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension); + } if (zend_stream_open(class_file, &file_handle TSRMLS_CC) == SUCCESS) { if (!file_handle.opened_path) { @@ -234,6 +248,7 @@ return zend_hash_exists(EG(class_table), (char*)lc_name, class_name_len+1); } } + efree(class_file); return 0; } /* }}} */ Index: tests/classes/namespace_001.phpt =================================================================== RCS file: tests/classes/namespace_001.phpt diff -N tests/classes/namespace_001.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/namespace_001.phpt 10 Aug 2005 02:56:02 -0000 @@ -0,0 +1,25 @@ +--TEST-- +Namespace: Simple Compile-Time Import +--FILE-- +<?php +require_once( dirname( __FILE__ ) . '/namespace_autoload.php' ); + +import ns:class1; +import ns:class2 as ns_class2; + +$full = new ns:class1(); +var_dump( $full->mem1 ); + +$alias = new class1(); +var_dump( $alias->mem1 ); + +$alias2 = new ns_class2(); +var_dump( $alias2->mem2 ); + +var_dump( ns_class2::$my_static ); +?> +--EXPECT-- +int(1) +int(1) +int(2) +string(14) "this is static" Index: tests/classes/namespace_002.phpt =================================================================== RCS file: tests/classes/namespace_002.phpt diff -N tests/classes/namespace_002.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/namespace_002.phpt 10 Aug 2005 02:56:02 -0000 @@ -0,0 +1,17 @@ +--TEST-- +Namespace: Runtime-Resolved Import +--FILE-- +<?php +require_once( dirname( __FILE__ ) . '/namespace_autoload.php' ); + +import ns:class1; + +$class1_str = 'class1'; +$c1 = new $class1_str(); +var_dump( $c1 ); +?> +--EXPECT-- +object(ns:class1)#1 (1) { + ["mem1"]=> + int(1) +} Index: tests/classes/namespace_003.phpt =================================================================== RCS file: tests/classes/namespace_003.phpt diff -N tests/classes/namespace_003.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/namespace_003.phpt 10 Aug 2005 02:56:02 -0000 @@ -0,0 +1,14 @@ +--TEST-- +Namespace: Private Classes +--FILE-- +<?php +require_once( dirname( __FILE__ ) . '/namespace_autoload.php' ); + +import ns:class3; + +$class3_str = 'class3'; +$c3 = new $class3_str(); +var_dump( $c3 ); +?> +--EXPECTREGEX-- +Fatal error: Cannot use class 'ns:class3' outside of its namespace, as it is private.* Index: tests/classes/namespace_004.phpt =================================================================== RCS file: tests/classes/namespace_004.phpt diff -N tests/classes/namespace_004.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/namespace_004.phpt 10 Aug 2005 02:56:02 -0000 @@ -0,0 +1,16 @@ +--TEST-- +Namespace: Public Derived/Private Base +--FILE-- +<?php +require_once( dirname( __FILE__ ) . '/namespace_autoload.php' ); + +import ns:class3_child; + +$c3 = new class3_child(); +$c3->printValue(); +$c3->callStatic(); +?> +--EXPECT-- +3 +static called + Index: tests/classes/namespace_005.phpt =================================================================== RCS file: tests/classes/namespace_005.phpt diff -N tests/classes/namespace_005.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/namespace_005.phpt 10 Aug 2005 02:56:02 -0000 @@ -0,0 +1,16 @@ +--TEST-- +Namespace: Namespace Import +--FILE-- +<?php +require_once( dirname( __FILE__ ) . '/namespace_autoload.php' ); + +import namespace ns; + +$c1 = new class1(); +var_dump( $c1 ); +?> +--EXPECT-- +object(ns:class1)#1 (1) { + ["mem1"]=> + int(1) +} Index: tests/classes/namespace_006.phpt =================================================================== RCS file: tests/classes/namespace_006.phpt diff -N tests/classes/namespace_006.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/namespace_006.phpt 10 Aug 2005 02:56:02 -0000 @@ -0,0 +1,12 @@ +--TEST-- +Namespace: Anonymous Namespace +--FILE-- +<?php +require_once( dirname( __FILE__ ) . '/namespace_anonymous.php' ); + +$c = new anon_class(); +var_dump( $c ); +?> +--EXPECTREGEX-- +inside anonymous namespace +.*Fatal error: Class \'anon_class\' not found.* Index: tests/classes/namespace_anonymous.php =================================================================== RCS file: tests/classes/namespace_anonymous.php diff -N tests/classes/namespace_anonymous.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/namespace_anonymous.php 10 Aug 2005 02:56:02 -0000 @@ -0,0 +1,12 @@ +<?php +namespace +{ + class anon_class + { + public $member = 'inside anonymous namespace'; + } +} + +$a = new anon_class(); +echo $a->member; +?> Index: tests/classes/namespace_autoload.php =================================================================== RCS file: tests/classes/namespace_autoload.php diff -N tests/classes/namespace_autoload.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/namespace_autoload.php 10 Aug 2005 02:56:02 -0000 @@ -0,0 +1,25 @@ +<?php +function __autoload($className) +{ + $directoryPrefix = dirname( __FILE__ ) . '/namespace/'; + + if( strpos( $className, ':' ) !== false ) + { + require_once( $directoryPrefix . str_replace( ':', '/', $className ) . '.php' ); + } + else + { + foreach( get_imported_namespaces( $className ) as $importNS ) + { + $tryPath = $directoryPrefix . str_replace( ':', '/', $importNS ) . "/${className}.php"; + + if( file_exists( $tryPath ) ) + { + require_once( $tryPath ); + autoload_import_class( $className, $importNS ); + break; + } + } + } +} +?>
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php