Attached is the latest version of the namespace patch! It finally includes namespace imports and it even includes anonymous namespace support. Also, the previous bison shift/reduce conflict has been removed. Here is a summary of its features:
- Simple imports: import ns:class1; - Import aliases: import ns:class1 as my_alias; - Namespace imports: import namespace ns; - Anonymous namespaces: namespace { class file_class{} } - Namespace-private classes: namespace ns{ private class prv_class{} } Two new functions have also been added to support namespace imports (more on that below): - get_imported_namespaces([$className]) Returns an array of imported namespaces for the current file. If a class name is passed, and this class is currently being autoloaded (also meaning that this function is called inside __autoload), then the list of returned imported namespaces is based on the file that triggered the __autoload call. - autoload_import_class($className, $namespaceName) Imports a class in a given namespace for the currently executing file (can ONLY be used inside __autoload!) Imports ------- Imports and namespace imports are handled completely by the user with the use of the __autloload function. This means that there are no restrictions on class file naming/directory structure. For simple imports, the class name will be passed with its full name (including the colons, such as "ns:class1"). For namespace imports, only the class name will be called. Since the user needs to determine which namespace (or namespaces) a class belongs to, the "get_imported_namespaces" function is provided to check the imported namespaces for the currently-executing file. Once the user is satisfied with a match, he/she needs to perform an "import" for this class, but this needs to be done on the executing file, not the file where __autoload is defined. For this reason, the autoload_import_class function is provided. A sample usage of both these functions is at tests/classes/namespace_autoload.php. Namespace-private classes ------------------------- Classes marked as "private" from within a namespace can only be used by classes defined in the same namespace. Anonymous namespaces -------------------- Classes defined inside anonymous namespaces can only be used within the file that declared the anonymous namespace. I believe the attached patch solves the issues that were presented long ago for namespaces. Referring to the post by Daniel Cogwill at http://www.zend.com/lists/engine2/200304/msg00164.html, the following are my answers to the problems he found at the time: 1) import-all silently hides local names. A: If a global class is defined with the same name as a class in a namespace, and the namespace class has been imported in the same script, the global class takes precedence. The namespace class can still be used by using its full name, i.e. namespace_name:class_name. 2) Interestingly (and I assume this is simply a bug), functions and classes behave differently wrt to import-all and duplicate definitions. A: Irrelevant in this patch. 3) There is no way to hide names from import (i.e. make a name non-exportable). This is a fundamental namespace feature, and there is already an appropriate keyword (private). A: Namespace-private classes are supported, using the "private" keyword. 4) The semantic meaning of successive imports depends on their relative ordering. A: The engine does not attempt to determine which class is included, the user decides the most appropriate behavior inside __autoload. 5) The most egregious issue is that an import in an included file affects the scope of the including file. A: Imports in this patch only affect the file they are in. Since I could not find a way to add the tests/classes/namespace directory and subdirectories, I zipped them separately, as before. Let me know if you have any questions on the attached patch. Best regards, Jessie Hernandez
? tests.tar.gz 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 2 Aug 2005 03:56:04 -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,24 @@ 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; + + /* 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 +490,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 +621,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 +655,17 @@ 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; *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 +720,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 +747,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 +759,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 +768,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 2 Aug 2005 03:56:05 -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,110 @@ } /* }}} */ +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; + 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 */ + zend_str_tolower(class_name, class_name_len); + + if (zend_hash_find(&EG(autoload_class_file_map), class_name, 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); + } + } else { + zend_hash_find(EG(import_namespace_table), zend_get_executed_filename(), strlen(zend_get_executed_filename()) + 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 = emalloc(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 2 Aug 2005 03:56:06 -0000 @@ -185,8 +185,26 @@ 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, ZVAL_DESTRUCTOR, 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, ZVAL_DESTRUCTOR, 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 +1392,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 +2655,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 +2708,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 +2721,179 @@ } } +/***************************** + * 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(); + 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; +} + +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); + } + + /* 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; + } + + /* initialize the full class name zval */ + INIT_ZVAL(alias_val); + Z_STRVAL(alias_val) = estrndup(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(alias_val), NULL) == FAILURE) { + zend_error(E_COMPILE_ERROR, "Could not import %s as %s!", Z_STRVAL(class_name->u.constant), alias_name_lc); + return; + } + + 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) = estrndup(Z_STRVAL(ns_name->u.constant), Z_STRLEN(ns_name->u.constant)); + Z_STRLEN(name_val) = Z_STRLEN(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 2 Aug 2005 03:56:06 -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 2 Aug 2005 03:56:07 -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)) != 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 @@ -949,6 +1082,11 @@ return FAILURE; } + /* insert the autoload class -> file mapping */ + INIT_ZVAL(executed_filename_val); + ZVAL_STRINGL(&executed_filename_val, zend_get_executed_filename(), strlen(zend_get_executed_filename()), 1); + zend_hash_add(&EG(autoload_class_file_map), 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,6 +1117,9 @@ zval_ptr_dtor(&class_name_ptr); + /* remove the autoload class -> file mapping */ + zend_hash_del(&EG(autoload_class_file_map), name, name_length + 1); + zend_hash_del(EG(in_autoload), lc_name, name_length+1); if (retval == FAILURE) { @@ -998,7 +1139,28 @@ } 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)) != 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 (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 2 Aug 2005 03:56:07 -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 2 Aug 2005 03:56:07 -0000 @@ -145,7 +145,9 @@ %token T_DOLLAR_OPEN_CURLY_BRACES %token T_CURLY_OPEN %token T_PAAMAYIM_NEKUDOTAYIM - +%token T_IMPORT +%token T_NAMESPACE_NAME +%token T_NAMESPACE %% /* Rules */ start: @@ -162,6 +164,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 +234,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 +291,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 +310,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 +461,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 +662,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 +679,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 @@ -910,6 +939,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 2 Aug 2005 03:56:08 -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; } @@ -1433,6 +1442,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: 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 2 Aug 2005 03:56:17 -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 2 Aug 2005 03:56:17 -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 2 Aug 2005 03:56:17 -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 2 Aug 2005 03:56:17 -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 2 Aug 2005 03:56:17 -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 2 Aug 2005 03:56:17 -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_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 2 Aug 2005 03:56:17 -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; + } + } + } +} +?>
tests.tar.gz
Description: GNU Zip compressed data
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php