As requested by others, attached is a cvs patch that includes the latest
namespace additions and PHP test files. With this patch, the following
features have been added:

1) import statements now include the class files, using a new .ini variable,
"class_path"!
2) Near-full support of private classes! Currently, private classes cannot
be used outside their namespace, but can be used within methods of classes
within the namespace. What's left for me to do is to allow private classes
to be extended from other classes in the same namespace (this is almost
complete in this patch, it works if both classes are defined in the same
file). Private classes are declared simply as "private class_name" within a
namespace (if the "private" keyword is applied to a class in the global
namespace, an error will be generated).

Aside from what's pending in #2, I think the only missing feature is
"namespace imports". I'd like to gather thoughts from others as how this
can be best implemented (some issues have been raised as how namespace
imports will work with opcode caches). I'll post a few possible approaches
some other day this week (I'm tired now ;-)).

BTW, I tried to do a "cvs add" to add my test files, but of course, it
failed with an "cvs add requires write access to repository" error. Hence,
I had to zip up the files separately. How can I add new files locally so
that cvs diff picks them up in the patch?


Regards,

Jessie Hernandez
? tests/classes/namespace
? tests/classes/namespace_001.phpt
? tests/classes/namespace_002.phpt
? tests/classes/namespace_003.phpt
? tests/classes/namespace_004.phpt
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	18 Jul 2005 04:52:28 -0000
@@ -34,10 +34,12 @@
 #   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

 #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)

 #endif
 
 #if defined(ZEND_WIN32) && ZEND_DEBUG
@@ -50,6 +52,7 @@
 ZEND_API zend_write_func_t zend_write;
 ZEND_API FILE *(*zend_fopen)(const char *filename, char **opened_path);
 ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC);
+ZEND_API int (*zend_stream_open_class_function)(const char *filename, zend_file_handle *handle TSRMLS_DC);

 ZEND_API void (*zend_block_interruptions)(void);
 ZEND_API void (*zend_unblock_interruptions)(void);
 ZEND_API void (*zend_ticks_function)(int ticks);
@@ -88,6 +91,7 @@
 HashTable *global_class_table;
 HashTable *global_constants_table;
 HashTable *global_auto_globals_table;
+HashTable *global_import_class_table;

 #endif
 
 ZEND_API zend_utility_values zend_uv;
@@ -430,6 +434,7 @@
 {
 	zend_function tmp_func;
 	zend_class_entry *tmp_class;
+	HashTable tmp_hash;

 
 	compiler_globals->compiled_filename = NULL;
 
@@ -443,6 +448,17 @@
 
 	zend_set_default_compile_time_values(TSRMLS_C);
 
+	/* initialize namespace variables */

+	compiler_globals->namespace_prefix = NULL;

+	compiler_globals->namespace_prefix_lc = NULL;

+	compiler_globals->namespace_prefix_len = 0;

+

+	/* initialize the import table */

+	compiler_globals->import_class_table = (HashTable *) malloc(sizeof(HashTable));

+	compiler_globals->current_import_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));

+

 	CG(interactive) = 0;
 
 	compiler_globals->auto_globals = (HashTable *) malloc(sizeof(HashTable));
@@ -465,6 +481,10 @@
 		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);

+	}

 }
 
 
@@ -565,6 +585,7 @@
 		zend_fopen = zend_fopen_wrapper;
 	}
 	zend_stream_open_function = utility_functions->stream_open_function;
+	zend_stream_open_class_function = utility_functions->stream_open_class_function;

 	zend_message_dispatcher_p = utility_functions->message_handler;
 	zend_block_interruptions = utility_functions->block_interruptions;
 	zend_unblock_interruptions = utility_functions->unblock_interruptions;
@@ -588,11 +609,13 @@
  	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));

 #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(&module_registry, 50, NULL, ZEND_MODULE_DTOR, 1, 0);
 	zend_init_rsrc_list_dtors();
@@ -618,10 +641,13 @@
 	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->current_import_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;

 
 	zend_hash_destroy(executor_globals->zend_constants);
 	*executor_globals->zend_constants = *GLOBAL_CONSTANTS_TABLE;
@@ -676,9 +702,11 @@
 	*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;

 	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);

 	compiler_globals_ctor(compiler_globals, tsrm_ls);
 	free(EG(zend_constants));
 	executor_globals_ctor(executor_globals, tsrm_ls);
@@ -699,6 +727,7 @@
 
 	zend_hash_destroy(GLOBAL_FUNCTION_TABLE);
 	zend_hash_destroy(GLOBAL_CLASS_TABLE);
+	zend_hash_destroy(GLOBAL_IMPORT_CLASS_TABLE);

 
 	zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE);
 	free(GLOBAL_AUTO_GLOBALS_TABLE);
@@ -709,6 +738,7 @@
 	zend_shutdown_constants(TSRMLS_C);
 	free(GLOBAL_FUNCTION_TABLE);
 	free(GLOBAL_CLASS_TABLE);
+	free(GLOBAL_IMPORT_CLASS_TABLE);

 #ifdef ZTS
 	zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC);
 	zend_hash_destroy(GLOBAL_CONSTANTS_TABLE);
@@ -716,6 +746,7 @@
 	GLOBAL_FUNCTION_TABLE = NULL;
 	GLOBAL_CLASS_TABLE = NULL;
 	GLOBAL_AUTO_GLOBALS_TABLE = NULL;
+	GLOBAL_IMPORT_CLASS_TABLE = NULL;

 #endif
 	zend_destroy_rsrc_list_dtors();
 }
Index: Zend/zend.h
===================================================================
RCS file: /repository/ZendEngine2/zend.h,v
retrieving revision 1.292
diff -u -r1.292 zend.h
--- Zend/zend.h	14 Jul 2005 14:01:02 -0000	1.292
+++ Zend/zend.h	18 Jul 2005 04:52:29 -0000
@@ -384,6 +384,7 @@
 	int (*stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC);
 	int (*vspprintf_function)(char **pbuf, size_t max_len, const char *format, va_list ap);
 	char *(*getenv_function)(char *name, size_t name_len TSRMLS_DC);
+	int (*stream_open_class_function)(const char *filename, zend_file_handle *handle TSRMLS_DC);
 } zend_utility_functions;
 
 		
@@ -519,6 +520,7 @@
 extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0);
 extern void (*zend_on_timeout)(int seconds TSRMLS_DC);
 extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC);
+extern ZEND_API int (*zend_stream_open_class_function)(const char *filename, zend_file_handle *handle TSRMLS_DC);
 extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap);
 extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC);
 
@@ -556,6 +558,7 @@
 #define ZMSG_MEMORY_LEAK_REPEATED		5L
 #define ZMSG_LOG_SCRIPT_NAME			6L
 #define ZMSG_MEMORY_LEAKS_GRAND_TOTAL	7L
+#define ZMSG_FAILED_IMPORT_CLASS		8L
 
 
 #define ZVAL_ADDREF(pz)		(++(pz)->refcount)
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	18 Jul 2005 04:52:30 -0000
@@ -185,8 +185,18 @@
 ZEND_API char *zend_set_compiled_filename(char *new_compiled_filename TSRMLS_DC)
 {
 	char **pp, *p;
+	HashTable file_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_imports, 10, NULL, ZVAL_DESTRUCTOR, 1);

+		zend_hash_add(CG(import_class_table), new_compiled_filename, length + 1, &file_imports, sizeof(file_imports), NULL);

+	}

+

+	 /* get the import class hashtable for this file */

+	zend_hash_find(CG(import_class_table), new_compiled_filename, length + 1, (void **)&CG(current_import_table));

+

 	if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp) == SUCCESS) {
 		CG(compiled_filename) = *pp;
 		return *pp;
@@ -1389,6 +1399,7 @@
 				zval_dtor(&class_name->u.constant);
 				break;
 			default:
+				zend_resolve_class_name_node(class_name TSRMLS_CC);

 				opline->op2 = *class_name;
 				break;
 		}
@@ -2626,6 +2637,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;
@@ -2680,8 +2696,231 @@
 		CG(doc_comment) = NULL;
 		CG(doc_comment_len) = 0;
 	}
-}
-
+

+}

+

+/*****************************

+ * BEGIN NAMESPACE FUNCTIONS *

+ *****************************/

+

+void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC)

+{

+	/* allocate space for the namespace prefix */

+	CG(namespace_prefix) = emalloc(ns_name->u.constant.value.str.len + 2);

+

+	/* get the namespace prefix */

+	strncpy(CG(namespace_prefix), ns_name->u.constant.value.str.val, ns_name->u.constant.value.str.len + 1);

+	strcat(CG(namespace_prefix), ":");

+

+	/* get the lowercased namespace prefix */

+	CG(namespace_prefix_lc) = zend_str_tolower_dup(CG(namespace_prefix), ns_name->u.constant.value.str.len + 1);

+

+	/* save the prefix length */

+	CG(namespace_prefix_len) = ns_name->u.constant.value.str.len + 1;

+}

+

+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;

+}

+

+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_generate_import_include_node(char *class_name, int class_name_len, znode *include_file_node)

+{

+	char *include_file = NULL;

+	int include_file_len = class_name_len + sizeof(".php") - 1;

+	char *include_file_ptr = NULL;

+

+	/* allocate enough space for the include file string */

+	include_file = emalloc(include_file_len + 1);

+	include_file_ptr = include_file;

+

+	/* copy the class name to the include file string, replacing colons with

+	   slashes */

+	for (; *class_name != '\0'; ++class_name, ++include_file_ptr)

+	{

+		if (*class_name != ':') {

+			*include_file_ptr = *class_name;

+		} else {

+			*include_file_ptr = '/';

+		}

+	}

+

+	/* add the .php extension */

+	strcpy(include_file_ptr, ".php");

+

+	/* create the include file node */

+	memset(include_file_node, 0, sizeof(znode));

+	include_file_node->op_type = IS_CONST;

+	include_file_node->u.constant.type = IS_STRING;

+	include_file_node->u.constant.value.str.val = include_file;

+	include_file_node->u.constant.value.str.len = include_file_len;

+}

+

+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(class_name->u.constant.value.str.val, ':');

+	znode include_file_node;

+	/* 'last_pos' is the position of the null terminator in the full class name */

+	char *last_pos = class_name->u.constant.value.str.val + class_name->u.constant.value.str.len;

+

+	if (colon_pos == NULL) {

+		zend_error(E_COMPILE_ERROR, "Cannot import non-namespace class: %s!", class_name->u.constant.value.str.val);

+		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(alias_name->u.constant.value.str.val, alias_name->u.constant.value.str.len);

+		alias_name_len = alias_name->u.constant.value.str.len;

+	}

+

+	/* make sure this import alias is not the same as a class name */

+	if (zend_hash_exists(CG(class_table), alias_name_lc, alias_name_len + 1)) {

+		zend_error(E_COMPILE_ERROR, "Could not import %s as %s: a class exists with the name %s", class_name->u.constant.value.str.val, alias_name_lc, alias_name_lc);

+		return;

+	}

+

+	/* make sure this import alias has not been used before */

+	if (zend_hash_exists(CG(current_import_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);

+	alias_val.value.str.val = estrdup(class_name->u.constant.value.str.val);

+	alias_val.value.str.len = class_name->u.constant.value.str.len;

+

+	/* add the alias */

+	if (zend_hash_add(CG(current_import_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!", class_name->u.constant.value.str.val, alias_name_lc);

+		return;

+	}

+

+	efree(alias_name_lc);

+

+	/* generate the include file opcode */

+	zend_generate_import_include_node(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len, &include_file_node);

+	zend_do_include_or_eval(ZEND_IMPORT_CLASS, result, &include_file_node TSRMLS_CC);

+}

+

+void zend_do_namespace_import(znode *ns_name TSRMLS_DC)

+{

+#ifdef JESSIE_0

+	char *class_path = estrdup(PG(class_path));

+	php_stream *dir = NULL;

+	char *ns_path = estrndup(ns_name->u.constant.value.str.val, ns_name->u.constant.value.str.len);

+	char *ns_path_ptr = ns_path;

+	char *path_begin = class_path;

+	char *path_end = NULL;

+	char trypath[MAXPATHLEN];

+

+	/* replace all colons with slashes in the namespace name */

+	while ((ns_path_ptr = strchr(ns_path_ptr, ':')) != NULL) {

+		*ns_path_ptr++ = '/';

+	}

+

+	while (path_begin && *path_begin) {

+		/* find the end of the next path */

+		path_end = strchr(path_begin, DEFAULT_DIR_SEPARATOR);

+

+		if (path_end != NULL) {

+			*path_end++ = '\0';

+		}

+

+		/* get the absolute path to try next */

+		snprintf(trypath, MAXPATHLEN, "%s/%s", path_begin, ns_path);

+

+		/* attempt to open this directory */

+		dir = php_class_files_wrapper.wops->dir_opener(&php_class_files_wrapper, trypath, "rb", 0, NULL, NULL STREAMS_CC TSRMLS_CC);

+

+		if (dir != NULL) {

+			php_stream_dirent class_file;

+

+			while (php_stream_readdir(dir, &class_file TSRMLS_CC) != NULL) {

+				printf("namespace file: %s\n", class_file.d_name);

+			}

+

+			php_stream_closedir(dir);

+			break;

+		}

+

+		path_begin = path_end;

+	}

+

+	efree(class_path);

+	efree(ns_path);

+#endif

+}

+

+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) + class_name->u.constant.value.str.len;

+		org_class_name = estrdup(class_name->u.constant.value.str.val);

+

+		STR_REALLOC(class_name->u.constant.value.str.val, new_length + 1);

+

+		/* get the full class name */

+		strncpy(class_name->u.constant.value.str.val, CG(namespace_prefix), CG(namespace_prefix_len) + 1);

+		strcat(class_name->u.constant.value.str.val, org_class_name);

+

+		/* get the new string length */

+		class_name->u.constant.value.str.len = new_length;

+

+		efree(org_class_name);

+	}

+}

+

+void zend_resolve_class_name_node(znode *class_name TSRMLS_DC)

+{

+	zval* mapped_class_name = NULL;

+	char *org_class_name = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);

+	zend_uint org_class_name_len = class_name->u.constant.value.str.len;

+

+	/* check to see if this class name is actually an import alias */

+	if (zend_hash_find(CG(current_import_table), org_class_name, org_class_name_len + 1, (void **)&mapped_class_name) == SUCCESS) {

+		/* free the class name string */

+		STR_FREE(class_name->u.constant.value.str.val);

+

+		/* set the class node to contain the full class name */

+		class_name->u.constant.value.str.val = estrdup(mapped_class_name->value.str.val);

+		class_name->u.constant.value.str.len = mapped_class_name->value.str.len;

+	}

+

+	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	18 Jul 2005 04:52:30 -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,14 @@
 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_namespace(znode *ns_token, znode *ns_name TSRMLS_DC);

+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_resolve_class_name_node(znode *class_name TSRMLS_DC);

+

 void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC);
 
 
@@ -621,6 +630,7 @@
 #define ZEND_INCLUDE_ONCE		(1<<2)
 #define ZEND_REQUIRE			(1<<3)
 #define ZEND_REQUIRE_ONCE		(1<<4)
+#define ZEND_IMPORT_CLASS		(1<<5)

 
 #define ZEND_ISSET				(1<<0)
 #define ZEND_ISEMPTY			(1<<1)
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	18 Jul 2005 04:52:30 -0000
@@ -135,6 +135,7 @@
 
 	EG(function_table) = CG(function_table);
 	EG(class_table) = CG(class_table);
+	EG(import_class_table) = CG(import_class_table);
 
 	EG(in_execution) = 0;
 	EG(in_autoload) = NULL;
@@ -906,6 +907,85 @@
 }
 
 
+char* zend_get_class_namespace(const zend_class_entry *ce)
+{
+	int namespace_length = 0;
+	char *result = NULL;
+	char *tmp = strrchr(ce->name, ':');
+ 
+	if (tmp != NULL) {
+		namespace_length = tmp - ce->name;
+
+		/* get the namespace name, which is everything before the last colon */
+		result = estrndup(ce->name, namespace_length);
+		zend_str_tolower(ce->name, namespace_length);
+	}
+ 
+	return result;
+}
+
+
+void zend_resolve_class_name_string(char **lc_name, int *lc_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);
+	zval* mapped_class_name = NULL;
+
+	if (zend_hash_find(EG(import_class_table), executed_filename, executed_filename_len + 1, (void **)&current_import_table) == SUCCESS) {
+		/* check to see if this class name is actually an import alias */
+		if (zend_hash_find(current_import_table, *lc_name, *lc_name_len + 1, (void **)&mapped_class_name) == SUCCESS) {
+			/* free the class name string */
+			free_alloca(*lc_name);
+
+			/* set the class node to contain the full class name */
+			*lc_name = do_alloca(mapped_class_name->value.str.len + 1);
+			zend_str_tolower_copy(*lc_name, mapped_class_name->value.str.val, mapped_class_name->value.str.len);
+			*lc_name_len = mapped_class_name->value.str.len;
+		}
+	}
+}
+
+
+zend_bool zend_verify_can_use_class(zend_class_entry *ce TSRMLS_DC)
+{
+	char *class_namespace = NULL;
+	char *current_namespace = NULL;
+	zend_bool result = SUCCESS;
+ 
+	if (ce->ce_flags & ZEND_ACC_PRIVATE) {
+		/* get the class' namespace */
+		class_namespace = zend_get_class_namespace(ce);
+ 
+		/* get the current namespace */
+		if (zend_is_compiling(TSRMLS_C)) {
+			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);
+			}
+		} else /* zend_is_executing */ {
+			if (EG(scope) != NULL) {
+				current_namespace = zend_get_class_namespace(EG(scope));
+			}
+		}
+ 
+		/* 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 */
+			zend_error(E_ERROR, "Cannot use class '%s' outside of its namespace, as it is private", ce->name);
+			result = FAILURE;
+		}
+ 
+		efree(class_namespace);
+		efree(current_namespace);
+ 	}
+ 
+	return result;
+}
+
+
 ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC)
 {
 	zval **args[1];
@@ -914,6 +994,7 @@
 	zval *retval_ptr;
 	int retval;
 	char *lc_name;
+	int lc_name_length = name_length;
 	zval *exception;
 	char dummy = 1;
 	zend_fcall_info fcall_info;
@@ -926,9 +1007,11 @@
 	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) {
+	zend_resolve_class_name_string(&lc_name, &lc_name_length TSRMLS_CC);
+
+	if (zend_hash_find(EG(class_table), lc_name, lc_name_length+1, (void **) ce) == SUCCESS) {
 		free_alloca(lc_name);
-		return SUCCESS;
+		return zend_verify_can_use_class(**ce TSRMLS_CC);
 	}
 
 	/* The compiler is not-reentrant. Make sure we __autoload() only during run-time
@@ -944,7 +1027,7 @@
 		zend_hash_init(EG(in_autoload), 0, NULL, NULL, 0);	
 	}
 	
-	if (zend_hash_add(EG(in_autoload), lc_name, name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
+	if (zend_hash_add(EG(in_autoload), lc_name, lc_name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
 		free_alloca(lc_name);
 		return FAILURE;
 	}
@@ -979,7 +1062,7 @@
 
 	zval_ptr_dtor(&class_name_ptr);
 
-	zend_hash_del(EG(in_autoload), lc_name, name_length+1);
+	zend_hash_del(EG(in_autoload), lc_name, lc_name_length+1);
 
 	if (retval == FAILURE) {
 		EG(exception) = exception;
@@ -997,8 +1080,13 @@
 		zval_ptr_dtor(&retval_ptr);
 	}
 
-	retval = zend_hash_find(EG(class_table), lc_name, name_length + 1, (void **) ce);
+	retval = zend_hash_find(EG(class_table), lc_name, lc_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	18 Jul 2005 04:52:31 -0000
@@ -143,6 +143,14 @@
 	zend_encoding_converter encoding_converter;
 	zend_encoding_oddlen encoding_oddlen;
 #endif /* ZEND_MULTIBYTE */
+

+	/* namespace variables */

+	char *namespace_prefix;

+	char *namespace_prefix_lc;

+	zend_uint namespace_prefix_len;

+

+	HashTable *import_class_table;

+	HashTable *current_import_table;

 };
 
 
@@ -232,6 +240,8 @@
 
 	zend_property_info std_property_info;
 
+	HashTable *import_class_table;	/* import class 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	18 Jul 2005 04:52:31 -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; }
 ;
 
@@ -305,6 +308,22 @@
 		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 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 +458,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 +659,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 +676,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 +936,10 @@
 	|	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_NAME { zend_do_import(&$$, &$2, NULL TSRMLS_CC); }
+	|	T_IMPORT T_NAMESPACE_NAME T_AS T_STRING { zend_do_import(&$$, &$2, &$4 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	18 Jul 2005 04:52:31 -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: Zend/zend_stream.c
===================================================================
RCS file: /repository/ZendEngine2/zend_stream.c,v
retrieving revision 1.12
diff -u -r1.12 zend_stream.c
--- Zend/zend_stream.c	7 Jul 2005 15:43:50 -0000	1.12
+++ Zend/zend_stream.c	18 Jul 2005 04:52:31 -0000
@@ -55,6 +55,11 @@
 	return (handle->handle.fp) ? SUCCESS : FAILURE;
 }
 
+ZEND_API int zend_stream_open_class(const char *filename, zend_file_handle *handle TSRMLS_DC)
+{
+	return zend_stream_open_class_function(filename, handle TSRMLS_CC);
+}
+
 ZEND_API int zend_stream_fixup(zend_file_handle *file_handle TSRMLS_DC)
 {
 	switch (file_handle->type) {
Index: Zend/zend_stream.h
===================================================================
RCS file: /repository/ZendEngine2/zend_stream.h,v
retrieving revision 1.7
diff -u -r1.7 zend_stream.h
--- Zend/zend_stream.h	4 Jun 2005 16:16:19 -0000	1.7
+++ Zend/zend_stream.h	18 Jul 2005 04:52:31 -0000
@@ -51,6 +51,7 @@
 
 BEGIN_EXTERN_C()
 ZEND_API int zend_stream_open(const char *filename, zend_file_handle *handle TSRMLS_DC);
+ZEND_API int zend_stream_open_class(const char *filename, zend_file_handle *handle TSRMLS_DC);
 ZEND_API int zend_stream_ferror(zend_file_handle *file_handle TSRMLS_DC);
 ZEND_API int zend_stream_getc(zend_file_handle *file_handle TSRMLS_DC);
 ZEND_API size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC);
Index: Zend/zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.53
diff -u -r1.53 zend_vm_def.h
--- Zend/zend_vm_def.h	11 Jul 2005 18:44:36 -0000	1.53
+++ Zend/zend_vm_def.h	18 Jul 2005 04:52:32 -0000
@@ -2672,11 +2672,19 @@
 
 	switch (opline->op2.u.constant.value.lval) {
 		case ZEND_INCLUDE_ONCE:
+		case ZEND_IMPORT_CLASS:
 		case ZEND_REQUIRE_ONCE: {
 				int dummy = 1;
 				zend_file_handle file_handle;
+				int successful = 0;
 
-				if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) {
+				if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) {
+					successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				} else {
+					successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				}
+
+				if (SUCCESS == successful) {
 
 					if (!file_handle.opened_path) {
 						file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len);
@@ -2692,8 +2700,10 @@
 				} else {
 					if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val);
-					} else {
+					} else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val);
+					} else {
+						zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val);
 					}
 				}
 				break;
Index: Zend/zend_vm_execute.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_execute.h,v
retrieving revision 1.56
diff -u -r1.56 zend_vm_execute.h
--- Zend/zend_vm_execute.h	11 Jul 2005 18:44:37 -0000	1.56
+++ Zend/zend_vm_execute.h	18 Jul 2005 04:52:36 -0000
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_vm_execute.h,v 1.56 2005/07/11 18:44:37 iliaa Exp $ */
+/* $Id: zend_vm_gen.php,v 1.11 2005/06/24 12:33:53 dmitry Exp $ */
 
 static opcode_handler_t zend_user_opcode_handlers[256] = {(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL,(opcode_handler_t)NULL};
 
@@ -1848,11 +1848,19 @@
 
 	switch (opline->op2.u.constant.value.lval) {
 		case ZEND_INCLUDE_ONCE:
+		case ZEND_IMPORT_CLASS:
 		case ZEND_REQUIRE_ONCE: {
 				int dummy = 1;
 				zend_file_handle file_handle;
+				int successful = 0;
 
-				if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) {
+				if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) {
+					successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				} else {
+					successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				}
+
+				if (SUCCESS == successful) {
 
 					if (!file_handle.opened_path) {
 						file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len);
@@ -1868,8 +1876,10 @@
 				} else {
 					if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val);
-					} else {
+					} else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val);
+					} else {
+						zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val);
 					}
 				}
 				break;
@@ -4264,11 +4274,19 @@
 
 	switch (opline->op2.u.constant.value.lval) {
 		case ZEND_INCLUDE_ONCE:
+		case ZEND_IMPORT_CLASS:
 		case ZEND_REQUIRE_ONCE: {
 				int dummy = 1;
 				zend_file_handle file_handle;
+				int successful = 0;
 
-				if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) {
+				if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) {
+					successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				} else {
+					successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				}
+
+				if (SUCCESS == successful) {
 
 					if (!file_handle.opened_path) {
 						file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len);
@@ -4284,8 +4302,10 @@
 				} else {
 					if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val);
-					} else {
+					} else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val);
+					} else {
+						zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val);
 					}
 				}
 				break;
@@ -7283,11 +7303,19 @@
 
 	switch (opline->op2.u.constant.value.lval) {
 		case ZEND_INCLUDE_ONCE:
+		case ZEND_IMPORT_CLASS:
 		case ZEND_REQUIRE_ONCE: {
 				int dummy = 1;
 				zend_file_handle file_handle;
+				int successful = 0;
 
-				if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) {
+				if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) {
+					successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				} else {
+					successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				}
+
+				if (SUCCESS == successful) {
 
 					if (!file_handle.opened_path) {
 						file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len);
@@ -7303,8 +7331,10 @@
 				} else {
 					if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val);
-					} else {
+					} else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val);
+					} else {
+						zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val);
 					}
 				}
 				break;
@@ -19322,11 +19352,19 @@
 
 	switch (opline->op2.u.constant.value.lval) {
 		case ZEND_INCLUDE_ONCE:
+		case ZEND_IMPORT_CLASS:
 		case ZEND_REQUIRE_ONCE: {
 				int dummy = 1;
 				zend_file_handle file_handle;
+				int successful = 0;
 
-				if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) {
+				if (opline->op2.u.constant.value.lval != ZEND_IMPORT_CLASS) {
+					successful = zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				} else {
+					successful = zend_stream_open_class(inc_filename->value.str.val, &file_handle TSRMLS_CC);
+				}
+
+				if (SUCCESS == successful) {
 
 					if (!file_handle.opened_path) {
 						file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len);
@@ -19342,8 +19380,10 @@
 				} else {
 					if (opline->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, inc_filename->value.str.val);
-					} else {
+					} else if (opline->op2.u.constant.value.lval==ZEND_REQUIRE_ONCE) {
 						zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, inc_filename->value.str.val);
+					} else {
+						zend_message_dispatcher(ZMSG_FAILED_IMPORT_CLASS, inc_filename->value.str.val);
 					}
 				}
 				break;
Index: Zend/zend_vm_opcodes.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_opcodes.h,v
retrieving revision 1.38
diff -u -r1.38 zend_vm_opcodes.h
--- Zend/zend_vm_opcodes.h	4 Jul 2005 13:24:46 -0000	1.38
+++ Zend/zend_vm_opcodes.h	18 Jul 2005 04:52:36 -0000
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: zend_vm_opcodes.h,v 1.38 2005/07/04 13:24:46 dmitry Exp $ */
+/* $Id: zend_vm_gen.php,v 1.11 2005/06/24 12:33:53 dmitry Exp $ */
 
 #define ZEND_NOP                       0
 #define ZEND_ADD                       1
Index: main/main.c
===================================================================
RCS file: /repository/php-src/main/main.c,v
retrieving revision 1.636
diff -u -r1.636 main.c
--- main/main.c	12 Jul 2005 16:53:29 -0000	1.636
+++ main/main.c	18 Jul 2005 04:52:39 -0000
@@ -292,6 +292,7 @@
 	STD_PHP_INI_ENTRY("error_log",				NULL,		PHP_INI_ALL,		OnUpdateString,			error_log,				php_core_globals,	core_globals)
 	STD_PHP_INI_ENTRY("extension_dir",			PHP_EXTENSION_DIR,		PHP_INI_SYSTEM,		OnUpdateStringUnempty,	extension_dir,			php_core_globals,	core_globals)
 	STD_PHP_INI_ENTRY("include_path",			PHP_INCLUDE_PATH,		PHP_INI_ALL,		OnUpdateStringUnempty,	include_path,			php_core_globals,	core_globals)
+	STD_PHP_INI_ENTRY("class_path",				PHP_INCLUDE_PATH,		PHP_INI_ALL,		OnUpdateStringUnempty,	class_path,			php_core_globals,	core_globals)
 	PHP_INI_ENTRY("max_execution_time",			"30",		PHP_INI_ALL,			OnUpdateTimeout)
 	STD_PHP_INI_ENTRY("open_basedir",			NULL,		PHP_INI_SYSTEM,		OnUpdateString,			open_basedir,			php_core_globals,	core_globals)
 	STD_PHP_INI_ENTRY("safe_mode_exec_dir",		PHP_SAFE_MODE_EXEC_DIR,	PHP_INI_SYSTEM,		OnUpdateString,			safe_mode_exec_dir,		php_core_globals,	core_globals)
@@ -868,6 +869,27 @@
 	return FAILURE;
 }
 
+static int php_stream_open_for_zend_class(const char *filename, zend_file_handle *handle TSRMLS_DC)
+{
+	php_stream *stream = php_stream_open_wrapper_class((char *)filename, "rb", ENFORCE_SAFE_MODE|USE_PATH|REPORT_ERRORS|STREAM_OPEN_FOR_INCLUDE, &handle->opened_path);
+
+	if (stream) {
+		handle->type = ZEND_HANDLE_STREAM;
+		handle->filename = (char*)filename;
+		handle->free_filename = 0;
+		handle->handle.stream.handle = stream;
+		handle->handle.stream.reader = (zend_stream_reader_t)_php_stream_read;
+		handle->handle.stream.closer = stream_closer_for_zend;
+		handle->handle.stream.fteller = stream_fteller_for_zend;
+		handle->handle.stream.interactive = 0;
+		/* suppress warning if this stream is not explicitly closed */
+		php_stream_auto_cleanup(stream);
+
+		return SUCCESS;
+	}
+	return FAILURE;
+}
+
 
 /* {{{ php_get_configuration_directive_for_zend
  */
@@ -897,6 +919,9 @@
 		case ZMSG_FAILED_REQUIRE_FOPEN:
 			php_error_docref("function.require" TSRMLS_CC, E_COMPILE_ERROR, "Failed opening required '%s' (include_path='%s')", php_strip_url_passwd((char *) data), STR_PRINT(PG(include_path)));
 			break;
+		case ZMSG_FAILED_IMPORT_CLASS:
+			php_error_docref("function.import" TSRMLS_CC, E_COMPILE_ERROR, "Failed opening required '%s' (class_path='%s')", php_strip_url_passwd((char *) data), STR_PRINT(PG(class_path)));
+			break;
 		case ZMSG_FAILED_HIGHLIGHT_FOPEN:
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed opening '%s' for highlighting", php_strip_url_passwd((char *) data));
 			break;
@@ -1368,6 +1393,7 @@
 	zuf.ticks_function = php_run_ticks;
 	zuf.on_timeout = php_on_timeout;
 	zuf.stream_open_function = php_stream_open_for_zend;
+	zuf.stream_open_class_function = php_stream_open_for_zend_class;
 	zuf.vspprintf_function = vspprintf;
 	zuf.getenv_function = sapi_getenv;
 	zend_startup(&zuf, NULL, 1);
Index: main/php_globals.h
===================================================================
RCS file: /repository/php-src/main/php_globals.h,v
retrieving revision 1.97
diff -u -r1.97 php_globals.h
--- main/php_globals.h	16 Mar 2004 19:49:19 -0000	1.97
+++ main/php_globals.h	18 Jul 2005 04:52:39 -0000
@@ -89,6 +89,7 @@
 	char *doc_root;
 	char *user_dir;
 	char *include_path;
+	char *class_path;
 	char *open_basedir;
 	char *extension_dir;
 
Index: main/php_streams.h
===================================================================
RCS file: /repository/php-src/main/php_streams.h,v
retrieving revision 1.102
diff -u -r1.102 php_streams.h
--- main/php_streams.h	16 May 2005 08:37:10 -0000	1.102
+++ main/php_streams.h	18 Jul 2005 04:52:40 -0000
@@ -511,11 +511,13 @@
 PHPAPI int php_register_url_stream_wrapper_volatile(char *protocol, php_stream_wrapper *wrapper TSRMLS_DC);
 PHPAPI int php_unregister_url_stream_wrapper_volatile(char *protocol TSRMLS_DC);
 PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
+PHPAPI php_stream *_php_stream_open_wrapper_class(char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC);
 PHPAPI php_stream_wrapper *php_stream_locate_url_wrapper(const char *path, char **path_for_open, int options TSRMLS_DC);
 PHPAPI char *php_stream_locate_eol(php_stream *stream, char *buf, size_t buf_len TSRMLS_DC);
 
 #define php_stream_open_wrapper(path, mode, options, opened)	_php_stream_open_wrapper_ex((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC)
 #define php_stream_open_wrapper_ex(path, mode, options, opened, context)	_php_stream_open_wrapper_ex((path), (mode), (options), (opened), (context) STREAMS_CC TSRMLS_CC)
+#define php_stream_open_wrapper_class(path, mode, options, opened)     _php_stream_open_wrapper_class((path), (mode), (options), (opened), NULL STREAMS_CC TSRMLS_CC)
 
 #define php_stream_get_from_zval(stream, zstream, mode, options, opened, context) \
 		if (Z_TYPE_PP((zstream)) == IS_RESOURCE) { \
Index: main/streams/plain_wrapper.c
===================================================================
RCS file: /repository/php-src/main/streams/plain_wrapper.c,v
retrieving revision 1.48
diff -u -r1.48 plain_wrapper.c
--- main/streams/plain_wrapper.c	24 Jun 2005 02:04:19 -0000	1.48
+++ main/streams/plain_wrapper.c	18 Jul 2005 04:52:40 -0000
@@ -917,11 +917,11 @@
 /* }}} */
 
 
-static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode,
-		int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+static php_stream *php_plain_files_stream_opener_ex(php_stream_wrapper *wrapper, char *path, char *mode,
+		int options, char **opened_path, char *include_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
 {
-	if ((options & USE_PATH) && PG(include_path) != NULL) {
-		return php_stream_fopen_with_path_rel(path, mode, PG(include_path), opened_path, options);
+	if ((options & USE_PATH) && include_path != NULL) {
+		return php_stream_fopen_with_path_rel(path, mode, include_path, opened_path, options);
 	}
 
 	if (((options & STREAM_DISABLE_OPEN_BASEDIR) == 0) && php_check_open_basedir(path TSRMLS_CC)) {
@@ -934,6 +934,18 @@
 	return php_stream_fopen_rel(path, mode, opened_path, options);
 }
 
+static php_stream *php_plain_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode,
+		int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+	return php_plain_files_stream_opener_ex(wrapper, path, mode, options, opened_path, PG(include_path), context STREAMS_CC TSRMLS_CC);
+}
+
+static php_stream *php_class_files_stream_opener(php_stream_wrapper *wrapper, char *path, char *mode,
+		int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+	return php_plain_files_stream_opener_ex(wrapper, path, mode, options, opened_path, PG(class_path), context STREAMS_CC TSRMLS_CC);
+}
+
 static int php_plain_files_url_stater(php_stream_wrapper *wrapper, char *url, int flags, php_stream_statbuf *ssb, php_stream_context *context TSRMLS_DC)
 {
 
@@ -1162,6 +1174,25 @@
 	0
 };
 
+static php_stream_wrapper_ops php_class_files_wrapper_ops = {
+	php_class_files_stream_opener,
+	NULL,
+	NULL,
+	php_plain_files_url_stater,
+	php_plain_files_dir_opener,
+	"classfile",
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+php_stream_wrapper php_class_files_wrapper = {
+	&php_class_files_wrapper_ops,
+	NULL,
+	0
+};
+
 /* {{{ php_stream_fopen_with_path */
 PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC)
 {
Index: main/streams/streams.c
===================================================================
RCS file: /repository/php-src/main/streams/streams.c,v
retrieving revision 1.81
diff -u -r1.81 streams.c
--- main/streams/streams.c	1 Jun 2005 15:11:44 -0000	1.81
+++ main/streams/streams.c	18 Jul 2005 04:52:41 -0000
@@ -40,6 +40,8 @@
 static int le_pstream = FAILURE; /* true global */
 static int le_stream_filter = FAILURE; /* true global */
 
+extern php_stream_wrapper php_class_files_wrapper;
+
 PHPAPI int php_file_le_stream(void)
 {
 	return le_stream;
@@ -1739,13 +1741,11 @@
 }
 /* }}} */
 
-/* {{{ php_stream_open_wrapper_ex */
-PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options,
-		char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+/* {{{ php_stream_open_wrapper_ex_ww */
+PHPAPI php_stream *_php_stream_open_wrapper_ex_ww(char *path, char *mode, int options,
+		char **opened_path, php_stream_wrapper *wrapper, char *path_to_open, php_stream_context *context STREAMS_DC TSRMLS_DC)
 {
 	php_stream *stream = NULL;
-	php_stream_wrapper *wrapper = NULL;
-	char *path_to_open;
 	int persistent = options & STREAM_OPEN_PERSISTENT;
 	char *copy_of_path = NULL;
 
@@ -1758,9 +1758,6 @@
 		return NULL;
 	}
 
-	path_to_open = path;
-
-	wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC);
 	if (options & STREAM_USE_URL && (!wrapper || !wrapper->is_url)) {
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "This function may only be used against URLs.");
 		return NULL;
@@ -1842,6 +1839,27 @@
 }
 /* }}} */
 
+/* {{{ php_stream_open_wrapper_ex */
+PHPAPI php_stream *_php_stream_open_wrapper_ex(char *path, char *mode, int options,
+		char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+	char *path_to_open = path;
+	php_stream_wrapper *wrapper = php_stream_locate_url_wrapper(path, &path_to_open, options TSRMLS_CC);
+
+	if (!path || !*path) {
+			return NULL;
+	}
+
+	return _php_stream_open_wrapper_ex_ww(path, mode, options, opened_path, wrapper, path_to_open, context STREAMS_CC TSRMLS_CC);
+}
+/* }}} */
+
+PHPAPI php_stream *_php_stream_open_wrapper_class(char *path, char *mode, int options,
+		char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC)
+{
+	return _php_stream_open_wrapper_ex_ww(path, mode, options, opened_path, &php_class_files_wrapper, path, context STREAMS_CC TSRMLS_CC);
+}
+
 /* {{{ context API */
 PHPAPI php_stream_context *php_stream_context_set(php_stream *stream, php_stream_context *context)
 {

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