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 **)¤t_import_table) == SUCCESS) {
+ /* make sure this import alias has not been used before */
+ if (zend_hash_exists(current_import_table, class_name_lc, class_name_len + 1)) {
+ zend_error(E_ERROR, "An import was already done with the %s alias", class_name);
+ efree(class_name_lc);
+ RETURN_FALSE;
+ }
+
+ /* get the full class name */
+ full_name_len = namespace_name_len + class_name_len + 1;
+ full_name = malloc(full_name_len + 1);
+ strncpy(full_name, namespace_name, namespace_name_len + 1);
+ strcat(full_name, ":");
+ strcat(full_name, class_name);
+
+ /* initialize the full class name zval */
+ INIT_ZVAL(import_val);
+ Z_STRVAL(import_val) = full_name;
+ Z_STRLEN(import_val) = full_name_len;
+
+ /* add the import alias */
+ if (zend_hash_add(current_import_table, class_name_lc, class_name_len + 1, &import_val, sizeof(import_val), NULL) == FAILURE) {
+ zend_error(E_ERROR, "Could not import %s", class_name);
+ efree(class_name_lc);
+ RETURN_FALSE;
+ }
+
+ efree(class_name_lc);
+ RETURN_TRUE;
+ }
+ } else {
+ zend_error(E_ERROR, "Class %s is not being autoloaded", class_name);
+ RETURN_FALSE;
+ }
+
+ efree(class_name_lc);
+ RETURN_FALSE;
+}
+/* }}} */
+
/* {{{ proto bool extension_loaded(string extension_name)
Returns true if the named extension is loaded */
ZEND_FUNCTION(extension_loaded)
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.644
diff -u -r1.644 zend_compile.c
--- Zend/zend_compile.c 17 Jul 2005 19:17:10 -0000 1.644
+++ Zend/zend_compile.c 10 Aug 2005 02:55:51 -0000
@@ -182,11 +182,34 @@
}
+void import_zval_dtor(zval *zv)
+{
+ free(Z_STRVAL_P(zv));
+}
+
ZEND_API char *zend_set_compiled_filename(char *new_compiled_filename TSRMLS_DC)
{
char **pp, *p;
+ HashTable file_class_imports;
+ HashTable file_namespace_imports;
int length = strlen(new_compiled_filename);
+ /* make sure the import class hashtable for this file exists */
+ if (!zend_hash_exists(CG(import_class_table), new_compiled_filename, length+1)) {
+ zend_hash_init(&file_class_imports, 10, NULL, (dtor_func_t) import_zval_dtor, 1);
+ zend_hash_add(CG(import_class_table), new_compiled_filename, length + 1, &file_class_imports, sizeof(file_class_imports), NULL);
+ }
+
+ /* make sure the import namespace hashtable for this file exists */
+ if (!zend_hash_exists(CG(import_namespace_table), new_compiled_filename, length+1)) {
+ zend_hash_init(&file_namespace_imports, 10, NULL, (dtor_func_t) import_zval_dtor, 1);
+ zend_hash_add(CG(import_namespace_table), new_compiled_filename, length + 1, &file_namespace_imports, sizeof(file_namespace_imports), NULL);
+ }
+
+ /* get the import hashtables for this file */
+ zend_hash_find(CG(import_class_table), new_compiled_filename, length + 1, (void **)&CG(current_import_class_table));
+ zend_hash_find(CG(import_namespace_table), new_compiled_filename, length + 1, (void **)&CG(current_import_namespace_table));
+
if (zend_hash_find(&CG(filenames_table), new_compiled_filename, length+1, (void **) &pp) == SUCCESS) {
CG(compiled_filename) = *pp;
return *pp;
@@ -1374,7 +1397,18 @@
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_FETCH_CLASS;
- SET_UNUSED(opline->op1);
+
+ if (CG(extending_child).type == IS_NULL) {
+ SET_UNUSED(opline->op1);
+ } else {
+ /* copy the child name */
+ INIT_ZVAL(opline->op1.u.constant);
+ opline->op1.op_type = IS_CONST;
+ opline->op1.u.constant.type = IS_STRING;
+ opline->op1.u.constant.value.str.val = estrndup(CG(extending_child).value.str.val, CG(extending_child).value.str.len);
+ opline->op1.u.constant.value.str.len = CG(extending_child).value.str.len;
+ }
+
opline->extended_value = ZEND_FETCH_CLASS_GLOBAL;
CG(catch_begin) = fetch_class_op_number;
if (class_name->op_type == IS_CONST) {
@@ -2626,6 +2660,11 @@
zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val);
}
+ /* fully prefix the class name */
+ efree(lcname);
+ zend_prefix_class_name_node(class_name TSRMLS_CC);
+ lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
+
new_class_entry->type = ZEND_USER_CLASS;
new_class_entry->name = class_name->u.constant.value.str.val;
new_class_entry->name_length = class_name->u.constant.value.str.len;
@@ -2674,6 +2713,11 @@
opline->result.op_type = IS_CONST;
CG(implementing_class) = opline->result;
+ /* if we are in an anonymous namespace, then immediately import this class */
+ if (CG(in_anonymous_namespace)) {
+ zend_do_import(NULL, class_name, NULL TSRMLS_CC);
+ }
+
if (CG(doc_comment)) {
CG(active_class_entry)->doc_comment = CG(doc_comment);
CG(active_class_entry)->doc_comment_len = CG(doc_comment_len);
@@ -2682,6 +2726,188 @@
}
}
+/*****************************
+ * BEGIN NAMESPACE FUNCTIONS *
+ *****************************/
+
+void zend_do_begin_extending(znode *child_name TSRMLS_DC)
+{
+ int name_len = Z_STRLEN(child_name->u.constant);
+
+ /* add the namespace prefix length, if applicable */
+ if (CG(namespace_prefix) != NULL) {
+ name_len += CG(namespace_prefix_len);
+ }
+
+ INIT_ZVAL(CG(extending_child));
+ CG(extending_child).type = IS_STRING;
+ Z_STRVAL(CG(extending_child)) = emalloc(name_len + 1);
+ Z_STRLEN(CG(extending_child)) = name_len;
+
+ if (CG(namespace_prefix) != NULL) {
+ /* copy the namespace prefix, then the child name */
+ strncpy(Z_STRVAL(CG(extending_child)), CG(namespace_prefix), CG(namespace_prefix_len) + 1);
+ strcat(Z_STRVAL(CG(extending_child)), Z_STRVAL(child_name->u.constant));
+ } else {
+ /* copy just the class name */
+ strncpy(Z_STRVAL(CG(extending_child)), Z_STRVAL(child_name->u.constant), Z_STRLEN(child_name->u.constant) + 1);
+ }
+}
+
+void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC)
+{
+ char *namespace_name = NULL;
+ int namespace_name_len = 0;
+
+ if (ns_name != NULL) {
+ namespace_name = Z_STRVAL(ns_name->u.constant);
+ namespace_name_len = Z_STRLEN(ns_name->u.constant);
+ } else {
+ /* this is an anonymous namespace */
+ CG(in_anonymous_namespace) = 1;
+ namespace_name = zend_get_compiled_filename(TSRMLS_C);
+ namespace_name_len = strlen(namespace_name);
+ }
+
+ /* allocate space for the namespace prefix */
+ CG(namespace_prefix) = emalloc(namespace_name_len + 2);
+
+ /* get the namespace prefix */
+ strncpy(CG(namespace_prefix), namespace_name, namespace_name_len + 1);
+ strcat(CG(namespace_prefix), ":");
+
+ /* get the lowercased namespace prefix */
+ CG(namespace_prefix_lc) = zend_str_tolower_dup(CG(namespace_prefix), namespace_name_len + 1);
+
+ /* save the prefix length */
+ CG(namespace_prefix_len) = namespace_name_len + 1;
+
+ /* we don't need the namespace name anymore, so free it */
+ if (ns_name != NULL) {
+ zval_dtor(&ns_name->u.constant);
+ }
+}
+
+void zend_do_end_extending(TSRMLS_D)
+{
+ efree(Z_STRVAL(CG(extending_child)));
+ CG(extending_child).type = IS_NULL;
+ Z_STRLEN(CG(extending_child)) = 0;
+ Z_STRVAL(CG(extending_child)) = NULL;
+}
+
+void zend_do_end_namespace(znode *ns_token TSRMLS_DC)
+{
+ /* free the string memory */
+ efree(CG(namespace_prefix));
+ efree(CG(namespace_prefix_lc));
+ CG(namespace_prefix_len) = 0;
+
+ /* set the prefixes to null */
+ CG(namespace_prefix) = NULL;
+ CG(namespace_prefix_lc) = NULL;
+
+ CG(in_anonymous_namespace) = 0;
+}
+
+void zend_do_verify_private_class(TSRMLS_D)
+{
+ if (CG(namespace_prefix) == NULL) {
+ zend_error(E_COMPILE_ERROR, "Cannot declare a private class in the global namespace");
+ }
+}
+
+void zend_do_import(znode *result, znode *class_name, znode *alias_name TSRMLS_DC)
+{
+ char *alias_name_lc = NULL;
+ zend_uint alias_name_len = 0;
+ zval alias_val;
+ /* 'colon_pos' is the position of the last colon in the full class name */
+ char *colon_pos = strrchr(Z_STRVAL(class_name->u.constant), ':');
+ /* 'last_pos' is the position of the null terminator in the full class name */
+ char *last_pos = Z_STRVAL(class_name->u.constant) + Z_STRLEN(class_name->u.constant);
+
+ if (colon_pos == NULL) {
+ zend_error(E_COMPILE_ERROR, "Cannot import non-namespace class: %s!", Z_STRVAL(class_name->u.constant));
+ return;
+ }
+
+ if (alias_name == NULL) {
+ /* advance to the first character of the class name */
+ ++colon_pos;
+
+ /* get the lowercased class name as the alias */
+ alias_name_len = last_pos - colon_pos;
+ alias_name_lc = zend_str_tolower_dup(colon_pos, alias_name_len);
+ } else /* alias_name != NULL */ {
+ alias_name_lc = zend_str_tolower_dup(Z_STRVAL(alias_name->u.constant), Z_STRLEN(alias_name->u.constant));
+ alias_name_len = Z_STRLEN(alias_name->u.constant);
+ zval_dtor(&alias_name->u.constant);
+ }
+
+ /* make sure this import alias has not been used before */
+ if (zend_hash_exists(CG(current_import_class_table), alias_name_lc, alias_name_len + 1)) {
+ zend_error(E_COMPILE_ERROR, "An import was already done with the %s alias", alias_name_lc);
+ return;
+ }
+
+ /* create the alias value */
+ INIT_ZVAL(alias_val);
+ Z_STRVAL(alias_val) = zend_strndup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
+ Z_STRLEN(alias_val) = Z_STRLEN(class_name->u.constant);
+
+ /* add the alias */
+ if (zend_hash_add(CG(current_import_class_table), alias_name_lc, alias_name_len + 1, &alias_val, sizeof(zval), NULL) == FAILURE) {
+ zend_error(E_COMPILE_ERROR, "Could not import %s as %s!", Z_STRVAL(class_name->u.constant), alias_name_lc);
+ }
+
+ zval_dtor(&class_name->u.constant);
+ efree(alias_name_lc);
+}
+
+void zend_do_namespace_import(znode *ns_name TSRMLS_DC)
+{
+ zval name_val;
+
+ INIT_ZVAL(name_val);
+ name_val.type = IS_STRING;
+ Z_STRVAL(name_val) = zend_strndup(Z_STRVAL(ns_name->u.constant), Z_STRLEN(ns_name->u.constant));
+ Z_STRLEN(name_val) = Z_STRLEN(ns_name->u.constant);
+
+ /* we don't need the namespace name anymore, so free it */
+ zval_dtor(&ns_name->u.constant);
+
+ if (zend_hash_next_index_insert(CG(current_import_namespace_table), &name_val, sizeof(name_val), NULL) == FAILURE) {
+ zend_error(E_COMPILE_ERROR, "Could not import namespace %s!", Z_STRVAL(ns_name->u.constant));
+ return;
+ }
+}
+
+void zend_prefix_class_name_node(znode *class_name TSRMLS_DC)
+{
+ zend_uint new_length = 0;
+ char *org_class_name = NULL;
+
+ if (CG(namespace_prefix) != NULL) {
+ new_length = CG(namespace_prefix_len) + Z_STRLEN(class_name->u.constant);
+ org_class_name = estrdup(Z_STRVAL(class_name->u.constant));
+
+ STR_REALLOC(Z_STRVAL(class_name->u.constant), new_length + 1);
+
+ /* get the full class name */
+ strncpy(Z_STRVAL(class_name->u.constant), CG(namespace_prefix), CG(namespace_prefix_len) + 1);
+ strcat(Z_STRVAL(class_name->u.constant), org_class_name);
+
+ /* get the new string length */
+ Z_STRLEN(class_name->u.constant) = new_length;
+
+ efree(org_class_name);
+ }
+}
+
+/***************************
+ * END NAMESPACE FUNCTIONS *
+ ***************************/
static void do_verify_abstract_class(TSRMLS_D)
{
Index: Zend/zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.315
diff -u -r1.315 zend_compile.h
--- Zend/zend_compile.h 7 Jul 2005 16:07:09 -0000 1.315
+++ Zend/zend_compile.h 10 Aug 2005 02:55:51 -0000
@@ -387,6 +387,7 @@
void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC);
int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier);
+void zend_do_verify_private_class(TSRMLS_D);
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
void zend_do_end_function_declaration(znode *function_token TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, znode *varname, zend_bool pass_by_reference TSRMLS_DC);
@@ -438,6 +439,15 @@
void zend_do_declare_implicit_property(TSRMLS_D);
void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC);
+void zend_do_begin_extending(znode *child_name TSRMLS_DC);
+void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC);
+void zend_do_end_extending(TSRMLS_D);
+void zend_do_end_namespace(znode *ns_token TSRMLS_DC);
+void zend_do_import(znode *result, znode *class_name, znode *alias_name TSRMLS_DC);
+void zend_do_namespace_import(znode *ns_name TSRMLS_DC);
+void zend_do_unimport_all(TSRMLS_D);
+void zend_prefix_class_name_node(znode *class_name TSRMLS_DC);
+
void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC);
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.327
diff -u -r1.327 zend_execute_API.c
--- Zend/zend_execute_API.c 12 Jul 2005 06:52:59 -0000 1.327
+++ Zend/zend_execute_API.c 10 Aug 2005 02:55:52 -0000
@@ -135,6 +135,8 @@
EG(function_table) = CG(function_table);
EG(class_table) = CG(class_table);
+ EG(import_class_table) = CG(import_class_table);
+ EG(import_namespace_table) = CG(import_namespace_table);
EG(in_execution) = 0;
EG(in_autoload) = NULL;
@@ -156,6 +158,8 @@
}
EG(active_symbol_table) = &EG(symbol_table);
+ zend_hash_init(&EG(autoload_class_file_map), 1, NULL, ZVAL_PTR_DTOR, 0);
+
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator TSRMLS_CC);
EG(opline_ptr) = NULL;
@@ -292,6 +296,8 @@
zend_hash_destroy(EG(in_autoload));
FREE_HASHTABLE(EG(in_autoload));
}
+
+ zend_hash_destroy(&EG(autoload_class_file_map));
} zend_end_try();
}
@@ -906,6 +912,112 @@
}
+char* zend_get_class_namespace(const char *class_name)
+{
+ int namespace_length = 0;
+ char *result = NULL;
+ char *tmp = strrchr(class_name, ':');
+
+ if (tmp != NULL) {
+ namespace_length = tmp - class_name;
+
+ /* get the namespace name, which is everything before the last colon */
+ result = estrndup(class_name, namespace_length);
+ zend_str_tolower(result, namespace_length);
+ }
+
+ return result;
+}
+
+
+zval *zend_resolve_class_name_string(char *name, int name_len TSRMLS_DC)
+{
+ HashTable *current_import_table = NULL;
+ char *executed_filename = zend_get_executed_filename(TSRMLS_C);
+ int executed_filename_len = strlen(executed_filename);
+ char *lc_name = NULL;
+ zval* mapped_class_name = NULL;
+
+ if (zend_hash_find(EG(import_class_table), executed_filename, executed_filename_len + 1, (void **)¤t_import_table) == SUCCESS) {
+ /* get the lowercased class name */
+ lc_name = zend_str_tolower_dup(name, name_len);
+
+ /* check to see if this class name is actually an import alias */
+ zend_hash_find(current_import_table, lc_name, name_len + 1, (void **)&mapped_class_name);
+
+ /* free the class name string */
+ efree(lc_name);
+ }
+
+ return mapped_class_name;
+}
+
+
+int zend_verify_can_use_class(zend_class_entry *ce TSRMLS_DC)
+{
+ int result = SUCCESS;
+
+ /* exit immediately if this is not a private class */
+ if ((ce->ce_flags & ZEND_ACC_PRIVATE) == 0) {
+ return SUCCESS;
+ }
+
+ /* check if we are in compilation mode */
+ if (zend_is_compiling(TSRMLS_C)) {
+ char *class_namespace = zend_get_class_namespace(ce->name);
+ char *current_namespace = NULL;
+
+ if (CG(namespace_prefix) != NULL) {
+ /* copy the namespace prefix minus the last character, which is a colon */
+ current_namespace = estrndup(CG(namespace_prefix), CG(namespace_prefix_len) - 1);
+ }
+
+ /* check if the namespaces match */
+ if (class_namespace != NULL
+ && (current_namespace == NULL
+ || strcmp(class_namespace, current_namespace) != 0)) {
+ /* the namespaces don't match, so don't allow use of this class */
+ result = FAILURE;
+ }
+
+ efree(class_namespace);
+ efree(current_namespace);
+ } else /* zend_is_executing */ {
+ char *class_namespace = zend_get_class_namespace(ce->name);
+ char *current_namespace = NULL;
+
+ if (active_opline->opcode == ZEND_FETCH_CLASS && active_opline->op1.op_type == IS_CONST) {
+ current_namespace = zend_get_class_namespace(active_opline->op1.u.constant.value.str.val);
+ } else if (EG(scope) != NULL) {
+ current_namespace = zend_get_class_namespace(EG(scope)->name);
+ }
+
+ /* check if the namespaces match */
+ if (class_namespace != NULL
+ && (current_namespace == NULL
+ || strcmp(class_namespace, current_namespace) != 0)) {
+ /* the namespaces don't match, so don't allow use of this class */
+ result = FAILURE;
+ }
+
+ if (class_namespace != NULL) {
+ efree(class_namespace);
+ }
+
+ if (current_namespace != NULL) {
+ efree(current_namespace);
+ }
+ }
+
+ /* generate the error message, if needed */
+ if (result == FAILURE) {
+ zend_error(E_ERROR, "Cannot use class '%s' outside of its namespace, as it is private", ce->name);
+ }
+
+ return result;
+}
+
+
ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC)
{
zval **args[1];
@@ -918,17 +1030,38 @@
char dummy = 1;
zend_fcall_info fcall_info;
zend_fcall_info_cache fcall_cache;
+ zval executed_filename_val;
+ zval *resolved_name = NULL;
if (name == NULL) {
return FAILURE;
}
-
+
lc_name = do_alloca(name_length + 1);
zend_str_tolower_copy(lc_name, name, name_length);
if (zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce) == SUCCESS) {
free_alloca(lc_name);
- return SUCCESS;
+ return zend_verify_can_use_class(**ce TSRMLS_CC);
+ }
+
+ /* try to resolve the class name and try again */
+ if ((resolved_name = zend_resolve_class_name_string(name, name_length TSRMLS_CC)) != NULL) {
+ /* get the new name */
+ name = estrndup(Z_STRVAL_P(resolved_name), Z_STRLEN_P(resolved_name));
+ name_length = Z_STRLEN_P(resolved_name);
+
+ /* get the lowercased version of the resolved name */
+ free_alloca(lc_name);
+ lc_name = do_alloca(name_length + 1);
+ zend_str_tolower_copy(lc_name, name, name_length);
+
+ /* try the search with the resolved name */
+ if (zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce) == SUCCESS) {
+ free_alloca(lc_name);
+ efree(name);
+ return zend_verify_can_use_class(**ce TSRMLS_CC);
+ }
}
/* The compiler is not-reentrant. Make sure we __autoload() only during run-time
@@ -936,6 +1069,11 @@
*/
if (zend_is_compiling(TSRMLS_C)) {
free_alloca(lc_name);
+
+ if (resolved_name != NULL) {
+ efree(name);
+ }
+
return FAILURE;
}
@@ -946,9 +1084,19 @@
if (zend_hash_add(EG(in_autoload), lc_name, name_length+1, (void**)&dummy, sizeof(char), NULL) == FAILURE) {
free_alloca(lc_name);
+
+ if (resolved_name != NULL) {
+ efree(name);
+ }
+
return FAILURE;
}
+ /* insert the autoload class -> file mapping */
+ INIT_ZVAL(executed_filename_val);
+ ZVAL_STRINGL(&executed_filename_val, zend_get_executed_filename(TSRMLS_C), strlen(zend_get_executed_filename(TSRMLS_C)), 1);
+ zend_hash_add(&EG(autoload_class_file_map), lc_name, name_length + 1, &executed_filename_val, sizeof(executed_filename_val), NULL);
+
ZVAL_STRINGL(&autoload_function, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)-1, 0);
ALLOC_ZVAL(class_name_ptr);
@@ -979,16 +1127,30 @@
zval_ptr_dtor(&class_name_ptr);
+ /* remove the autoload class -> file mapping */
+ zend_hash_del(&EG(autoload_class_file_map), name, name_length + 1);
+ zval_dtor(&executed_filename_val);
+
zend_hash_del(EG(in_autoload), lc_name, name_length+1);
if (retval == FAILURE) {
EG(exception) = exception;
free_alloca(lc_name);
+
+ if (resolved_name != NULL) {
+ efree(name);
+ }
+
return FAILURE;
}
if (EG(exception) && exception) {
free_alloca(lc_name);
+
+ if (resolved_name != NULL) {
+ efree(name);
+ }
+
zend_error(E_ERROR, "Function %s(%s) threw an exception of type '%s'", ZEND_AUTOLOAD_FUNC_NAME, name, Z_OBJCE_P(EG(exception))->name);
return FAILURE;
}
@@ -998,7 +1160,32 @@
}
retval = zend_hash_find(EG(class_table), lc_name, name_length + 1, (void **) ce);
+
+ /* try to resolve the class name after the autoload and try again */
+ if (retval == FAILURE && (resolved_name = zend_resolve_class_name_string(name, name_length TSRMLS_CC)) != NULL) {
+ /* get the new name */
+ name = estrndup(Z_STRVAL_P(resolved_name), Z_STRLEN_P(resolved_name));
+ name_length = Z_STRLEN_P(resolved_name);
+
+ /* get the lowercased version of the resolved name */
+ free_alloca(lc_name);
+ lc_name = do_alloca(name_length + 1);
+ zend_str_tolower_copy(lc_name, name, name_length);
+
+ /* try the search with the resolved name */
+ retval = zend_hash_find(EG(class_table), lc_name, name_length+1, (void **) ce);
+ }
+
free_alloca(lc_name);
+
+ if (resolved_name != NULL) {
+ efree(name);
+ }
+
+ if (retval == SUCCESS) {
+ retval = zend_verify_can_use_class(**ce TSRMLS_CC);
+ }
+
return retval;
}
Index: Zend/zend_globals.h
===================================================================
RCS file: /repository/ZendEngine2/zend_globals.h,v
retrieving revision 1.140
diff -u -r1.140 zend_globals.h
--- Zend/zend_globals.h 3 Nov 2004 23:13:32 -0000 1.140
+++ Zend/zend_globals.h 10 Aug 2005 02:55:52 -0000
@@ -143,6 +143,17 @@
zend_encoding_converter encoding_converter;
zend_encoding_oddlen encoding_oddlen;
#endif /* ZEND_MULTIBYTE */
+
+ /* namespace-related variables */
+ zend_bool in_anonymous_namespace;
+ char *namespace_prefix;
+ char *namespace_prefix_lc;
+ zend_uint namespace_prefix_len;
+ HashTable *import_class_table;
+ HashTable *import_namespace_table;
+ HashTable *current_import_class_table;
+ HashTable *current_import_namespace_table;
+ zval extending_child;
};
@@ -232,6 +243,10 @@
zend_property_info std_property_info;
+ HashTable autoload_class_file_map;
+ HashTable *import_class_table;
+ HashTable *import_namespace_table;
+
void *reserved[ZEND_MAX_RESERVED_RESOURCES];
};
Index: Zend/zend_language_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_language_parser.y,v
retrieving revision 1.159
diff -u -r1.159 zend_language_parser.y
--- Zend/zend_language_parser.y 4 Jul 2005 13:24:44 -0000 1.159
+++ Zend/zend_language_parser.y 10 Aug 2005 02:55:52 -0000
@@ -145,7 +145,10 @@
%token T_DOLLAR_OPEN_CURLY_BRACES
%token T_CURLY_OPEN
%token T_PAAMAYIM_NEKUDOTAYIM
-
+%token T_IMPORT
+%token T_NAMESPACE_NAME
+%token T_NAMESPACE
+%token T_NAMESPACE_C
%% /* Rules */
start:
@@ -162,6 +165,7 @@
statement
| function_declaration_statement { zend_do_early_binding(TSRMLS_C); }
| class_declaration_statement { zend_do_early_binding(TSRMLS_C); }
+ | namespace_declaration_statement
| T_HALT_COMPILER '(' ')' ';' { REGISTER_MAIN_LONG_CONSTANT("__COMPILER_HALT_OFFSET__", zend_get_scanned_file_offset(TSRMLS_C), CONST_CS); YYACCEPT; }
;
@@ -231,6 +235,8 @@
'{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); }
| T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
+ | T_IMPORT T_NAMESPACE_NAME ';' { zend_do_import(&$$, &$2, NULL TSRMLS_CC); }
+ | T_IMPORT T_NAMESPACE_NAME T_AS T_STRING ';' { zend_do_import(&$$, &$2, &$4 TSRMLS_CC); }
;
@@ -286,8 +292,8 @@
;
unticked_class_declaration_statement:
- class_entry_type T_STRING extends_from
- { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
+ class_entry_type T_STRING { zend_do_begin_extending(&$2 TSRMLS_CC); } extends_from { zend_do_end_extending(TSRMLS_C); }
+ { zend_do_begin_class_declaration(&$1, &$2, &$4 TSRMLS_CC); }
implements_list
'{'
class_statement_list
@@ -305,6 +311,23 @@
T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = 0; }
| T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
| T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_FINAL_CLASS; }
+ | T_PRIVATE T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE; }
+ | T_PRIVATE T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
+ | T_PRIVATE T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); zend_do_verify_private_class(TSRMLS_C); $$.u.EA.type = ZEND_ACC_PRIVATE | ZEND_ACC_FINAL_CLASS; }
+;
+
+namespace_declaration_statement:
+ T_NAMESPACE '{' { zend_do_begin_namespace(&$1, NULL TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$1 TSRMLS_CC); }
+ | T_NAMESPACE namespace_name '{' { zend_do_begin_namespace(&$1, &$2 TSRMLS_CC); } namespace_statement_list '}' { zend_do_end_namespace(&$1 TSRMLS_CC); }
+;
+
+namespace_statement_list:
+ namespace_statement_list namespace_statement
+ | /* empty */
+;
+
+namespace_statement:
+ class_declaration_statement { zend_do_early_binding(TSRMLS_C); }
;
extends_from:
@@ -439,6 +462,7 @@
optional_class_type:
/* empty */ { $$.op_type = IS_UNUSED; }
| T_STRING { $$ = $1; }
+ | T_NAMESPACE_NAME { $$ = $1; }
| T_ARRAY { $$.op_type = IS_CONST; $$.u.constant.type=IS_NULL;}
;
@@ -639,10 +663,12 @@
fully_qualified_class_name:
T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
+ | T_NAMESPACE_NAME { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
;
class_name_reference:
T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
+ | T_NAMESPACE_NAME { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
| dynamic_class_name_reference { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
;
@@ -654,6 +680,10 @@
| base_variable { $$ = $1; }
;
+namespace_name:
+ T_NAMESPACE_NAME { $$ = $1; }
+ | T_STRING { $$ = $1; }
+;
dynamic_class_name_variable_properties:
dynamic_class_name_variable_properties dynamic_class_name_variable_property
@@ -687,6 +717,7 @@
| T_CLASS_C { $$ = $1; }
| T_METHOD_C { $$ = $1; }
| T_FUNC_C { $$ = $1; }
+ | T_NAMESPACE_C { $$ = $1; }
;
@@ -910,6 +941,8 @@
| T_EVAL '(' expr ')' { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); }
| T_REQUIRE expr { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); }
| T_REQUIRE_ONCE expr { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); }
+ | T_IMPORT T_NAMESPACE T_NAMESPACE_NAME { zend_do_namespace_import(&$3 TSRMLS_CC); }
+ | T_IMPORT T_NAMESPACE T_STRING { zend_do_namespace_import(&$3 TSRMLS_CC); }
;
isset_variables:
Index: Zend/zend_language_scanner.l
===================================================================
RCS file: /repository/ZendEngine2/zend_language_scanner.l,v
retrieving revision 1.129
diff -u -r1.129 zend_language_scanner.l
--- Zend/zend_language_scanner.l 16 Jun 2005 13:31:21 -0000 1.129
+++ Zend/zend_language_scanner.l 10 Aug 2005 02:55:52 -0000
@@ -790,6 +790,7 @@
ESCAPED_AND_WHITESPACE [\n\t\r #'.:;,()|^&+-/*=%!~<>[EMAIL PROTECTED]
ANY_CHAR (.|[\n])
NEWLINE ("\r"|"\n"|"\r\n")
+NAMESPACE_NAME ({LABEL}":")*{LABEL}
%option noyylineno
%option noyywrap
@@ -923,6 +924,14 @@
return T_CLASS;
}
+<ST_IN_SCRIPTING>"namespace" {
+ return T_NAMESPACE;
+}
+
+<ST_IN_SCRIPTING>"import" {
+ return T_IMPORT;
+}
+
<ST_IN_SCRIPTING>"interface" {
return T_INTERFACE;
}
@@ -1301,6 +1310,25 @@
return T_FUNC_C;
}
+<ST_IN_SCRIPTING>"__NAMESPACE__" {
+ char *namespace_name = NULL;
+ int namespace_name_len = 0;
+
+ if (CG(namespace_prefix)) {
+ namespace_name = CG(namespace_prefix);
+ namespace_name_len = CG(namespace_prefix_len);
+ }
+
+ if (!namespace_name) {
+ namespace_name = ":";
+ namespace_name_len = 1;
+ }
+ zendlval->value.str.len = namespace_name_len - 1;
+ zendlval->value.str.val = estrndup(namespace_name, zendlval->value.str.len);
+ zendlval->type = IS_STRING;
+ return T_NAMESPACE_C;
+}
+
<ST_IN_SCRIPTING>"__METHOD__" {
char *class_name = CG(active_class_entry) ? CG(active_class_entry)->name : NULL;
char *func_name = CG(active_op_array)? CG(active_op_array)->function_name : NULL;
@@ -1433,6 +1461,13 @@
return T_STRING;
}
+<ST_IN_SCRIPTING>{NAMESPACE_NAME} {
+ zendlval->value.str.val = (char *)estrndup(yytext, yyleng);
+ zendlval->value.str.len = yyleng;
+ zendlval->type = IS_STRING;
+ return T_NAMESPACE_NAME;
+}
+
<ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>{LABEL} {
zend_copy_value(zendlval, yytext, yyleng);
zendlval->type = IS_STRING;
Index: ext/spl/php_spl.c
===================================================================
RCS file: /repository/php-src/ext/spl/php_spl.c,v
retrieving revision 1.49
diff -u -r1.49 php_spl.c
--- ext/spl/php_spl.c 17 Jun 2005 16:42:53 -0000 1.49
+++ ext/spl/php_spl.c 10 Aug 2005 02:56:00 -0000
@@ -203,7 +203,21 @@
zend_op_array *new_op_array;
zval *result = NULL;
- class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension);
+ /* if the class name contains one or more colons, then replace these with
+ the directory separators */
+ if (strchr(lc_name, ':') != NULL) {
+ char *lc_name_cpy = estrndup(lc_name, class_name_len);
+ char *lc_name_bak = lc_name_cpy;
+
+ while((lc_name_bak = strchr(lc_name_bak, ':')) != NULL) {
+ *lc_name_bak++ = DEFAULT_SLASH;
+ }
+
+ class_file_len = spprintf(&class_file, 0, "%s%s", lc_name_cpy, file_extension);
+ efree(lc_name_cpy);
+ } else {
+ class_file_len = spprintf(&class_file, 0, "%s%s", lc_name, file_extension);
+ }
if (zend_stream_open(class_file, &file_handle TSRMLS_CC) == SUCCESS) {
if (!file_handle.opened_path) {
@@ -234,6 +248,7 @@
return zend_hash_exists(EG(class_table), (char*)lc_name, class_name_len+1);
}
}
+
efree(class_file);
return 0;
} /* }}} */
Index: tests/classes/namespace_001.phpt
===================================================================
RCS file: tests/classes/namespace_001.phpt
diff -N tests/classes/namespace_001.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/classes/namespace_001.phpt 10 Aug 2005 02:56:02 -0000
@@ -0,0 +1,25 @@
+--TEST--
+Namespace: Simple Compile-Time Import
+--FILE--
+<?php
+require_once( dirname( __FILE__ ) . '/namespace_autoload.php' );
+
+import ns:class1;
+import ns:class2 as ns_class2;
+
+$full = new ns:class1();
+var_dump( $full->mem1 );
+
+$alias = new class1();
+var_dump( $alias->mem1 );
+
+$alias2 = new ns_class2();
+var_dump( $alias2->mem2 );
+
+var_dump( ns_class2::$my_static );
+?>
+--EXPECT--
+int(1)
+int(1)
+int(2)
+string(14) "this is static"
Index: tests/classes/namespace_002.phpt
===================================================================
RCS file: tests/classes/namespace_002.phpt
diff -N tests/classes/namespace_002.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/classes/namespace_002.phpt 10 Aug 2005 02:56:02 -0000
@@ -0,0 +1,17 @@
+--TEST--
+Namespace: Runtime-Resolved Import
+--FILE--
+<?php
+require_once( dirname( __FILE__ ) . '/namespace_autoload.php' );
+
+import ns:class1;
+
+$class1_str = 'class1';
+$c1 = new $class1_str();
+var_dump( $c1 );
+?>
+--EXPECT--
+object(ns:class1)#1 (1) {
+ ["mem1"]=>
+ int(1)
+}
Index: tests/classes/namespace_003.phpt
===================================================================
RCS file: tests/classes/namespace_003.phpt
diff -N tests/classes/namespace_003.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/classes/namespace_003.phpt 10 Aug 2005 02:56:02 -0000
@@ -0,0 +1,14 @@
+--TEST--
+Namespace: Private Classes
+--FILE--
+<?php
+require_once( dirname( __FILE__ ) . '/namespace_autoload.php' );
+
+import ns:class3;
+
+$class3_str = 'class3';
+$c3 = new $class3_str();
+var_dump( $c3 );
+?>
+--EXPECTREGEX--
+Fatal error: Cannot use class 'ns:class3' outside of its namespace, as it is private.*
Index: tests/classes/namespace_004.phpt
===================================================================
RCS file: tests/classes/namespace_004.phpt
diff -N tests/classes/namespace_004.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/classes/namespace_004.phpt 10 Aug 2005 02:56:02 -0000
@@ -0,0 +1,16 @@
+--TEST--
+Namespace: Public Derived/Private Base
+--FILE--
+<?php
+require_once( dirname( __FILE__ ) . '/namespace_autoload.php' );
+
+import ns:class3_child;
+
+$c3 = new class3_child();
+$c3->printValue();
+$c3->callStatic();
+?>
+--EXPECT--
+3
+static called
+
Index: tests/classes/namespace_005.phpt
===================================================================
RCS file: tests/classes/namespace_005.phpt
diff -N tests/classes/namespace_005.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/classes/namespace_005.phpt 10 Aug 2005 02:56:02 -0000
@@ -0,0 +1,16 @@
+--TEST--
+Namespace: Namespace Import
+--FILE--
+<?php
+require_once( dirname( __FILE__ ) . '/namespace_autoload.php' );
+
+import namespace ns;
+
+$c1 = new class1();
+var_dump( $c1 );
+?>
+--EXPECT--
+object(ns:class1)#1 (1) {
+ ["mem1"]=>
+ int(1)
+}
Index: tests/classes/namespace_006.phpt
===================================================================
RCS file: tests/classes/namespace_006.phpt
diff -N tests/classes/namespace_006.phpt
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/classes/namespace_006.phpt 10 Aug 2005 02:56:02 -0000
@@ -0,0 +1,12 @@
+--TEST--
+Namespace: Anonymous Namespace
+--FILE--
+<?php
+require_once( dirname( __FILE__ ) . '/namespace_anonymous.php' );
+
+$c = new anon_class();
+var_dump( $c );
+?>
+--EXPECTREGEX--
+inside anonymous namespace
+.*Fatal error: Class \'anon_class\' not found.*
Index: tests/classes/namespace_anonymous.php
===================================================================
RCS file: tests/classes/namespace_anonymous.php
diff -N tests/classes/namespace_anonymous.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/classes/namespace_anonymous.php 10 Aug 2005 02:56:02 -0000
@@ -0,0 +1,12 @@
+<?php
+namespace
+{
+ class anon_class
+ {
+ public $member = 'inside anonymous namespace';
+ }
+}
+
+$a = new anon_class();
+echo $a->member;
+?>
Index: tests/classes/namespace_autoload.php
===================================================================
RCS file: tests/classes/namespace_autoload.php
diff -N tests/classes/namespace_autoload.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/classes/namespace_autoload.php 10 Aug 2005 02:56:02 -0000
@@ -0,0 +1,25 @@
+<?php
+function __autoload($className)
+{
+ $directoryPrefix = dirname( __FILE__ ) . '/namespace/';
+
+ if( strpos( $className, ':' ) !== false )
+ {
+ require_once( $directoryPrefix . str_replace( ':', '/', $className ) . '.php' );
+ }
+ else
+ {
+ foreach( get_imported_namespaces( $className ) as $importNS )
+ {
+ $tryPath = $directoryPrefix . str_replace( ':', '/', $importNS ) . "/${className}.php";
+
+ if( file_exists( $tryPath ) )
+ {
+ require_once( $tryPath );
+ autoload_import_class( $className, $importNS );
+ break;
+ }
+ }
+ }
+}
+?>
tests.tar.gz
Description: GNU Zip compressed data
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
