Hello Andi,

Attached is the latest version of the patch and some test support files that
I had to zip up because I couldn't "cvs add" new directories.

Let me know what you think and of any improvements I could make to the code.
Thanks!


Best regards,

Jessie


Andi Gutmans wrote:

> I definitely prefer sticking to just classes as I agree this is what most
> people really need it for (and it wouldn't get us into the trouble we got
> into when we tried to achieve the holy grail of namespaces).
> Can you please send me an updated version of the patch to review?
> 
> At 08:34 AM 8/12/2005 +0200, Marcus Boerger wrote:
>>Hello Jessie,
>>
>>   don't overcomplicate it, just stay with classes.
>>
>>marcus
>>
>>Friday, August 12, 2005, 5:50:08 AM, you wrote:
>>
>> > Right now, my patch is complete as respects classes inside namespaces,
>> > simple import, namespace imports, etc. I just made a few changes
>> > locally to see how feasible it was to allow functions inside
>> > namespaces, and it was actually very simple. Like classes, the
>> > functions internally are prefixed with the namespace name and a colon,
>> > e.g.:
>>
>> > <?php
>> > namespace test_ns
>> > {
>> >     function test_func
>> >     {
>> >         echo "hello!\n";
>> >     }
>> > }
>>
>> > test_func(); // generates an error, 'test_func' does not exist
>>
>> > test_ns:test_func(); // prints "hello!"
>>?>>
>>
>>
>> > I haven't done anything with functions as regards imports, and I think
>> > it would be difficult/useless to do so. Simple imports might be easy,
>> > but what about namespace imports? There is no such concept as
>> > __autoload for functions, so namespace imports for functions would be
>> > discarded. Also, if you import foo:bar, you don't know if this is a
>> > function or a class. The former syntax of "import function/class foo
>> > from bar" would need to be used, and this syntax was very ugly IMHO.
>>
>> > So, I ask, would it be useful to have functions inside namespaces and
>> > only use it as above? Imports would only work for classes, and the only
>> > change would be that you can reference functions with a colon (of
>> > course, just like classes, you cannot declare a function name with a
>> > colon, only reference it).
>>
>> > Let me know what you guys think. My Beta 2 patch is working great as it
>> > is, and I suspect the majority of the users who want namespaces is to
>> > simply group/organize their classes anyways.
>>
>>
>> > Regards,
>>
>> > Jessie Hernandez
>>
>>
>>
>>
>>Best regards,
>>  Marcus
>>
>>--
>>PHP Internals - PHP Runtime Development Mailing List
>>To unsubscribe, visit: http://www.php.net/unsub.php
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 **)&current_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 **)&current_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;
+			}
+		}
+	}
+}
+?>

Attachment: tests.tar.gz
Description: GNU Zip compressed data

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to