Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:31823 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 43668 invoked by uid 1010); 22 Aug 2007 02:40:46 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 43653 invoked from network); 22 Aug 2007 02:40:46 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 22 Aug 2007 02:40:46 -0000 Authentication-Results: pb1.pair.com smtp.mail=greg@chiaraquartet.net; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=greg@chiaraquartet.net; sender-id=unknown Received-SPF: error (pb1.pair.com: domain chiaraquartet.net from 38.99.98.18 cause and error) X-PHP-List-Original-Sender: greg@chiaraquartet.net X-Host-Fingerprint: 38.99.98.18 beast.bluga.net Linux 2.6 Received: from [38.99.98.18] ([38.99.98.18:44606] helo=mail.bluga.net) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 0F/80-40210-A22ABC64 for ; Tue, 21 Aug 2007 22:40:44 -0400 Received: from mail.bluga.net (localhost.localdomain [127.0.0.1]) by mail.bluga.net (Postfix) with ESMTP id 753B8C0D805 for ; Tue, 21 Aug 2007 19:40:39 -0700 (MST) Received: from [192.168.0.106] (CPE-76-84-1-170.neb.res.rr.com [76.84.1.170]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.bluga.net (Postfix) with ESMTP id 8E4B0C0D804 for ; Tue, 21 Aug 2007 19:40:38 -0700 (MST) Message-ID: <46CBA2B6.2010600@chiaraquartet.net> Date: Tue, 21 Aug 2007 21:43:02 -0500 User-Agent: Thunderbird 1.5.0.12 (X11/20070604) MIME-Version: 1.0 To: internals Mailing List Content-Type: multipart/mixed; boundary="------------000600050902020301030305" X-Virus-Scanned: ClamAV using ClamSMTP Subject: [PATCH] bracketed namespace, unset import, removal of namespace blah; From: greg@chiaraquartet.net (Gregory Beaver) --------------000600050902020301030305 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Hi again, The attached patch: 1) adds "unset import" syntax for declaring a namespace to have local import scope (it does NOT affect variable scope or the global class/function table) 2) removes "namespace Name;" syntax (this I am happy to add this back in if there is uproar) 3) fixes all misspellings of "coflict" in zend_compile.c (2 total) 4) uses a more intuitive error message "Namespace 'Foo' cannot be nested (already within 'Bar' namespace)" for nested namespaces 5) updates tests to use brackets it can also be found at http://pear.php.net/~greg/namespace_brackets_unsetimport.patch.txt After Stanislav's criticisms of my "smart import" namespace patch and David's criticism of confusing dual syntax, I decided to take another approach to the import issue. Although I would rather only support one use case of namespace blah {}, I do think that realistically PHP should be as intuitive as possible. Having a separate scope by default for import that does not inherit from the global scope is not very intuitive. So, instead of resetting current_import by default, this patch makes import global by default and local by explicit syntax via: namespace MyNamespace unset import { } For example: This code demonstrates that in the (useless) namespace last {} declaration, we can access the global import. This way, since import conflicts are not the norm but the exception, they can be handled on a case-by-case basis. Let's remember that in most cases users will not be declaring multiple namespaces, but instead doing this use case for the import keyword: Again, the primary use case for multiple namespaces in the same file that I hope to support is combining multiple pre-existing files into a single file. As each file is expected to be self-contained, this means that by having import statements within the namespace {} declaration and using unset import the files are guaranteed to combine with any other separate file that follows these rules. Even if authors do not use unset import, it can easily be added by hand or automatically when glomming the separate files into a single file. Files with global imports will be out of luck if there are naming conflicts with the global namespace (similar to today's pre-namespace conundrum), but as class files or functions are almost always libraries of some kind, this is unlikely if the documentation is clear on best practices. Greg --------------000600050902020301030305 Content-Type: text/plain; name="namespace_brackets_unsetimport.patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="namespace_brackets_unsetimport.patch.txt" ? halt_compiler_php6.patch.txt ? namespace.patch.txt ? namespace_brackets_unsetimport.patch.txt ? namespace_smartimport.patch.txt Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.762 diff -u -r1.762 zend_compile.c --- Zend/zend_compile.c 20 Aug 2007 09:48:41 -0000 1.762 +++ Zend/zend_compile.c 22 Aug 2007 02:15:54 -0000 @@ -166,6 +166,7 @@ CG(labels) = NULL; CG(current_namespace) = NULL; CG(current_import) = NULL; + CG(saved_import) = NULL; } /* }}} */ @@ -3192,7 +3193,7 @@ /* Class name must not conflict with import names */ if (CG(current_import) && zend_u_hash_exists(CG(current_import), Z_TYPE(class_name->u.constant), lcname, lcname_len+1)) { - zend_error(E_COMPILE_ERROR, "Class name '%R' coflicts with import name", Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant)); + zend_error(E_COMPILE_ERROR, "Class name '%R' conflicts with import name", Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant)); } if (CG(current_namespace)) { @@ -4971,11 +4972,8 @@ unsigned int lcname_len; zstr lcname; - if (CG(active_op_array)->last > 0) { - zend_error(E_COMPILE_ERROR, "Namespace declaration statement has to be the very first statement in the script"); - } if (CG(current_namespace)) { - zend_error(E_COMPILE_ERROR, "Namespace cannot be declared twice"); + zend_error(E_COMPILE_ERROR, "Namespace '%R' cannot be nested (already within '%R' namespace)", Z_TYPE(name->u.constant), Z_UNIVAL(name->u.constant), Z_TYPE_P(CG(current_namespace)), Z_UNIVAL_P(CG(current_namespace))); } lcname = zend_u_str_case_fold(Z_TYPE(name->u.constant), Z_UNIVAL(name->u.constant), Z_UNILEN(name->u.constant), 0, &lcname_len); if (((lcname_len == sizeof("self")-1) && @@ -4991,6 +4989,33 @@ } /* }}} */ +void zend_do_end_namespace(TSRMLS_D) /* {{{ */ +{ + if (CG(current_namespace)) { + zval_dtor(CG(current_namespace)); + efree(CG(current_namespace)); + CG(current_namespace) = NULL; + } + if (CG(saved_import)) { + if (CG(current_import)) { + zend_hash_destroy(CG(current_import)); + efree(CG(current_import)); + CG(current_import) = NULL; + } + CG(current_import) = CG(saved_import); + CG(saved_import) = NULL; + } +} +/* }}} */ + +/* within a namespace, do not use the global import list */ +void zend_do_local_import(TSRMLS_D) /* {{{ */ +{ + CG(saved_import) = CG(current_import); + CG(current_import) = NULL; +} +/* }}} */ + void zend_do_import(znode *ns_name, znode *new_name TSRMLS_DC) /* {{{ */ { unsigned int lcname_len; @@ -5042,7 +5067,7 @@ } if (zend_u_hash_exists(CG(class_table), Z_TYPE_P(name), lcname, lcname_len+1)) { - zend_error(E_COMPILE_ERROR, "Import name '%R' coflicts with defined class", Z_TYPE_P(name), Z_UNIVAL_P(name)); + zend_error(E_COMPILE_ERROR, "Import name '%R' conflicts with defined class", Z_TYPE_P(name), Z_UNIVAL_P(name)); } if (zend_u_hash_add(CG(current_import), Z_TYPE_P(name), lcname, lcname_len+1, &ns, sizeof(zval*), NULL) != SUCCESS) { @@ -5068,6 +5093,11 @@ efree(CG(current_import)); CG(current_import) = NULL; } + if (CG(saved_import)) { + zend_hash_destroy(CG(saved_import)); + efree(CG(saved_import)); + CG(saved_import) = NULL; + } } /* }}} */ Index: Zend/zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.363 diff -u -r1.363 zend_compile.h --- Zend/zend_compile.h 20 Aug 2007 09:48:41 -0000 1.363 +++ Zend/zend_compile.h 22 Aug 2007 02:15:55 -0000 @@ -521,6 +521,8 @@ void zend_do_build_namespace_name(znode *result, znode *prefix, znode *name TSRMLS_DC); void zend_do_namespace(znode *name TSRMLS_DC); +void zend_do_end_namespace(TSRMLS_D); +void zend_do_local_import(TSRMLS_D); void zend_do_import(znode *name, znode *new_name TSRMLS_DC); void zend_do_end_compilation(TSRMLS_D); Index: Zend/zend_globals.h =================================================================== RCS file: /repository/ZendEngine2/zend_globals.h,v retrieving revision 1.168 diff -u -r1.168 zend_globals.h --- Zend/zend_globals.h 12 Jul 2007 09:23:48 -0000 1.168 +++ Zend/zend_globals.h 22 Aug 2007 02:15:55 -0000 @@ -140,6 +140,7 @@ zval *current_namespace; HashTable *current_import; + HashTable *saved_import; #ifdef ZTS HashTable **static_members; Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.188 diff -u -r1.188 zend_language_parser.y --- Zend/zend_language_parser.y 20 Aug 2007 09:48:41 -0000 1.188 +++ Zend/zend_language_parser.y 22 Aug 2007 02:15:56 -0000 @@ -171,11 +171,15 @@ | function_declaration_statement { zend_do_early_binding(TSRMLS_C); } | class_declaration_statement { zend_do_early_binding(TSRMLS_C); } | T_HALT_COMPILER '(' ')' ';' { zend_do_halt_compiler_register(TSRMLS_C); YYACCEPT; } - | T_NAMESPACE namespace_name ';' { zend_do_namespace(&$2 TSRMLS_CC); } + | T_NAMESPACE namespace_name unimport '{' { zend_do_namespace(&$2 TSRMLS_CC);} top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } + | T_NAMESPACE namespace_name '{' { zend_do_namespace(&$2 TSRMLS_CC);} top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } | T_IMPORT namespace_name ';' { zend_do_import(&$2, NULL TSRMLS_CC); } | T_IMPORT namespace_name T_AS T_STRING ';' { zend_do_import(&$2, &$4 TSRMLS_CC); } ; +unimport: + T_UNSET T_IMPORT { zend_do_local_import(TSRMLS_C); } +; inner_statement_list: inner_statement_list { zend_do_extended_info(TSRMLS_C); } inner_statement { HANDLE_INTERACTIVE(); } Index: Zend/tests/ns_001.phpt =================================================================== RCS file: /repository/ZendEngine2/tests/ns_001.phpt,v retrieving revision 1.1 diff -u -r1.1 ns_001.phpt --- Zend/tests/ns_001.phpt 12 Jul 2007 09:23:48 -0000 1.1 +++ Zend/tests/ns_001.phpt 22 Aug 2007 02:15:56 -0000 @@ -2,7 +2,7 @@ 001: Class in namespace --FILE-- bar(); test::ns1::Foo::baz(); +} --EXPECT-- test::ns1::Foo test::ns1::Foo Index: Zend/tests/ns_002.phpt =================================================================== RCS file: /repository/ZendEngine2/tests/ns_002.phpt,v retrieving revision 1.1 diff -u -r1.1 ns_002.phpt --- Zend/tests/ns_002.phpt 12 Jul 2007 09:23:48 -0000 1.1 +++ Zend/tests/ns_002.phpt 22 Aug 2007 02:15:56 -0000 @@ -2,7 +2,7 @@ 002: Import in namespace --FILE--