For previewing purposes, I have attached a patch of what I have so far so
that others can look at it and try it out. I have also attached two PHP
files for testing (_testns.php is the script that should be run after the
patch is applied. This script includes a class from class3.php to
demonstrate two things: namespaces may be spread out in files, and classes
do not have to be immediately available for imports to work).

I based my patch on PHP 5.1.0b2 (not CVS, yet). I have not used the diff
utility before, but here is the command I ran to produce the patch (let me
know if there's a better way):

diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend php-5.1.0b2/Zend/ >
ns.patch

Anyways, all the features I've mentioned have been enabled in the patch
except the following:

1) Automatic including of class files.
2) Wildcard imports (or full namespace imports).

I have been checking the code to see what it would take to apply the current
include/require logic against a different INI variable (class_path), but I
digged deeper and deeper into the code and got lost in the streams
functions. So far, it seems I have to create my own opcode (like
ZEND_INCLUDE_OR_EVAL), and when that's encountered, then call whatever
stream function is needed to perform the include against class_path. It
seems like it will take me some time to figure this out, so that's why I
haven't included it yet (maybe someone can help me?).

Please try it out and let me know what you think. I believe this solution
compiles the code to be the equivalent of prefixing all classes, so I think
most of the issues presented in the archives are solved with this solution.
Let me know if you need anything else from me to get it working on your
installation. Also, I'm not sure if there are any attachment restrictions
in this group (email me privately if you can't open the files).


--
Jessie

Attachment: _class3.php
Description: application/php

diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend.c php-5.1.0b2/Zend/zend.c
--- php-5.1.0b2-bak/Zend/zend.c	2005-06-15 15:05:55.000000000 -0400
+++ php-5.1.0b2/Zend/zend.c	2005-07-09 00:44:41.000000000 -0400
@@ -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
@@ -88,6 +90,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 +433,7 @@
 {
 	zend_function tmp_func;
 	zend_class_entry *tmp_class;
+	zval tmp_zval;

 
 	compiler_globals->compiled_filename = NULL;
 
@@ -443,6 +447,16 @@
 
 	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));

+	zend_hash_init_ex(compiler_globals->import_class_table, 10, NULL, ZVAL_DESTRUCTOR, 1, 0);

+    zend_hash_copy(compiler_globals->import_class_table, global_import_class_table, NULL, &tmp_zval, sizeof(zval));

+

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

+	}

 }
 
 
@@ -588,11 +606,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, ZVAL_DESTRUCTOR, 1, 0);

 
 	zend_hash_init_ex(&module_registry, 50, NULL, ZEND_MODULE_DTOR, 1, 0);
 	zend_init_rsrc_list_dtors();
@@ -618,10 +638,12 @@
 	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->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 +698,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 +723,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 +734,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 +742,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();
 }
diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_compile.c php-5.1.0b2/Zend/zend_compile.c
--- php-5.1.0b2-bak/Zend/zend_compile.c	2005-06-22 04:32:57.000000000 -0400
+++ php-5.1.0b2/Zend/zend_compile.c	2005-07-09 00:44:41.000000000 -0400
@@ -1385,10 +1384,12 @@
 				zval_dtor(&class_name->u.constant);
 				break;
 			default:
+				zend_resolve_class_name_node(class_name TSRMLS_CC);

 				opline->op2 = *class_name;
 				break;
 		}
 	} else {
+		zend_resolve_class_name_node(class_name TSRMLS_CC);

 		opline->op2 = *class_name;
 	}
 	opline->result.u.var = get_temporary_variable(CG(active_op_array));
@@ -2615,6 +2616,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;
@@ -2659,8 +2665,151 @@
 		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);

+	*CG(namespace_prefix) = '\0';

+

+	/* get the namespace prefix */

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

+	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_import(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, ':');

+	/* '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(import_class_table), alias_name_lc, alias_name_len + 1)) {

+		zend_error(E_COMPILE_ERROR, "An import was already done with the %s alias", alias_name_lc);

+		return;

+	}

+

+	/* initialize the full class name zval */

+	INIT_ZVAL(alias_val);

+	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(import_class_table), alias_name_lc, alias_name_len + 1, &alias_val, sizeof(alias_val), NULL) == FAILURE) {

+		zend_error(E_COMPILE_ERROR, "Could not import %s as %s!", class_name->u.constant.value.str.val, alias_name_lc);

+		return;

+	}

+

+	efree(alias_name_lc);

+}

+

+void zend_do_namespace_import(znode *ns_name TSRMLS_DC)

+{

+}

+

+void zend_do_unimport_all(TSRMLS_D)

+{

+	zend_hash_clean(CG(import_class_table));

+}

+

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

+

+		/* prepare for strcat */

+		*class_name->u.constant.value.str.val = '\0';

+

+		/* get the full class name */

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

+		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(import_class_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)
 {
diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_compile.h php-5.1.0b2/Zend/zend_compile.h
--- php-5.1.0b2-bak/Zend/zend_compile.h	2005-06-22 04:32:57.000000000 -0400
+++ php-5.1.0b2/Zend/zend_compile.h	2005-07-09 00:44:41.000000000 -0400
@@ -438,6 +438,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 *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);
 
 
diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_globals.h php-5.1.0b2/Zend/zend_globals.h
--- php-5.1.0b2-bak/Zend/zend_globals.h	2004-11-03 18:13:32.000000000 -0500
+++ php-5.1.0b2/Zend/zend_globals.h	2005-07-09 00:44:41.000000000 -0400
@@ -143,6 +143,13 @@
 	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;

 };
 
 
diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_language_parser.y php-5.1.0b2/Zend/zend_language_parser.y
--- php-5.1.0b2-bak/Zend/zend_language_parser.y	2005-06-08 02:49:00.000000000 -0400
+++ php-5.1.0b2/Zend/zend_language_parser.y	2005-07-09 02:20:28.000000000 -0400
@@ -145,11 +145,13 @@
 %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:
-	top_statement_list
+	top_statement_list { zend_do_unimport_all(TSRMLS_C); }
 ;
 
 top_statement_list:
@@ -162,6 +164,7 @@
 		statement
 	|	function_declaration_statement	{ zend_do_early_binding(TSRMLS_C); }
 	|	class_declaration_statement		{ zend_do_early_binding(TSRMLS_C); }
+	|	namespace_declaration_statement
 	|	T_HALT_COMPILER '(' ')' ';'   { REGISTER_MAIN_LONG_CONSTANT("__COMPILER_HALT_OFFSET__", zend_get_scanned_file_offset(TSRMLS_C), CONST_CS); YYACCEPT; }
 ;
 
@@ -231,6 +234,10 @@
 		'{' 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); }
+	|	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); }
 ;
 
 
@@ -307,6 +314,19 @@
 	|	T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = 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:
 		/* empty */					{ $$.op_type = IS_UNUSED; }
 	|	T_EXTENDS fully_qualified_class_name	{ $$ = $2; }
@@ -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
Only in php-5.1.0b2/Zend/: zend_language_parser.y~
diff -Bbruw -X diff_exclude.txt php-5.1.0b2-bak/Zend/zend_language_scanner.l php-5.1.0b2/Zend/zend_language_scanner.l
--- php-5.1.0b2-bak/Zend/zend_language_scanner.l	2005-06-16 09:31:21.000000000 -0400
+++ php-5.1.0b2/Zend/zend_language_scanner.l	2005-07-09 00:44:41.000000000 -0400
@@ -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;

Attachment: _testns.php
Description: application/php

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

Reply via email to