Hi all,

This patch is also available at
http://pear.php.net/~greg/namespace.patch.txt

The patch adds the syntax "namespace { *stuff }" and allows multiple
namespaces per file with no performance penalty or added complexity as
only 4 lines of code need to be changed, and 9 lines of code added to
implement this support!

Basically, there is one use case of multiple namespaces per file that
the patch is designed to support, which is the ability to cram many
files into a single file.  I have done this for purposes of distributing
things (prior to phar), it is used by some with phing tasks for
performance reasons, and can have other uses as well.

The patch provides the ability to do this, for example:

<?php
namespace One {
    require_once 'blah.php';
    class MyClass extends blah
    {
        function test()
        {
            echo "OK\n";
        }
    }
    function test()
    {
        echo "OK\n";
    }
}

namespace Two {
    class MyClass
    {
        function test()
        {
            echo "OK\n";
        }
    }
    function test()
    {
        echo "OK\n";
    }
}
?>

Note that the old format "namespace OneRingToRuleThemAll;" is still
fully supported, and should be the recommended format, as build tools
can easily take an entire file, change namespace .*; into namespace .*{
and append <?php } ?> to the end of the file.

The attached patch is against php6, but as you can see, a blind monkey
could port it to PHP_5_3 when the time comes.  All of the introduced
changes are now tested, including the error message for nested namespace
declarations, and the error message for multiple namespace declarations
with ; (which was previously untested by .phpt tests)

Thanks,
Greg
? halt_compiler_php6.patch.txt
? namespace.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 20 Aug 2007 19:46:52 -0000
@@ -4966,16 +4966,16 @@
 }
 /* }}} */
 
-void zend_do_namespace(znode *name TSRMLS_DC) /* {{{ */
+void zend_do_namespace(znode *name, int brackets TSRMLS_DC) /* {{{ */
 {
        unsigned int lcname_len;
        zstr lcname;
 
-       if (CG(active_op_array)->last > 0) {
+       if (!brackets && 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 cannot be declared twice 
(without brackets) or nested within brackets");
        }
        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 +4991,16 @@
 }
 /* }}} */
 
+void zend_do_end_namespace(TSRMLS_D) /* {{{ */
+{
+       if (CG(current_namespace)) {
+               zval_dtor(CG(current_namespace));
+               efree(CG(current_namespace));
+               CG(current_namespace) = NULL;
+       }
+}
+/* }}} */
+
 void zend_do_import(znode *ns_name, znode *new_name TSRMLS_DC) /* {{{ */
 {
        unsigned int lcname_len;
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 20 Aug 2007 19:46:53 -0000
@@ -520,7 +520,8 @@
 void zend_do_abstract_method(znode *function_name, znode *modifiers, znode 
*body TSRMLS_DC);
 
 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_namespace(znode *name, int brackets TSRMLS_DC);
+void zend_do_end_namespace(TSRMLS_D);
 void zend_do_import(znode *name, znode *new_name TSRMLS_DC);
 void zend_do_end_compilation(TSRMLS_D);
 
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 20 Aug 2007 19:46:54 -0000
@@ -171,12 +171,12 @@
        |       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 ';'  { zend_do_namespace(&$2, 0 
TSRMLS_CC); }
+       |       T_NAMESPACE namespace_name '{'  { zend_do_namespace(&$2, 1 
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); }
 ;
 
-
 inner_statement_list:
                inner_statement_list  { zend_do_extended_info(TSRMLS_C); } 
inner_statement { HANDLE_INTERACTIVE(); }
        |       /* empty */
Index: Zend/tests/ns_039.phpt
===================================================================
RCS file: Zend/tests/ns_039.phpt
diff -N Zend/tests/ns_039.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Zend/tests/ns_039.phpt      20 Aug 2007 19:46:54 -0000
@@ -0,0 +1,14 @@
+--TEST--
+039: double namespace declaration
+--FILE--
+<?php
+namespace Exception;
+namespace Oops;
+function foo() {
+  echo "ok\n";
+}
+Exception::foo();
+Exception::bar();
+--EXPECTF--
+Fatal error: Namespace cannot be declared twice (without brackets) or nested 
within brackets in %sns_039.php on line 3
+
Index: Zend/tests/ns_040.phpt
===================================================================
RCS file: Zend/tests/ns_040.phpt
diff -N Zend/tests/ns_040.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Zend/tests/ns_040.phpt      20 Aug 2007 19:46:54 -0000
@@ -0,0 +1,14 @@
+--TEST--
+040: namespace not first declaration
+--FILE--
+<?php
+$a = oops;
+namespace Exception;
+function foo() {
+  echo "ok\n";
+}
+Exception::foo();
+Exception::bar();
+--EXPECTF--
+Fatal error: Namespace declaration statement has to be the very first 
statement in the script in %sns_040.php on line 3
+
Index: Zend/tests/ns_041.phpt
===================================================================
RCS file: Zend/tests/ns_041.phpt
diff -N Zend/tests/ns_041.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Zend/tests/ns_041.phpt      20 Aug 2007 19:46:54 -0000
@@ -0,0 +1,13 @@
+--TEST--
+041: namespace with brackets, function declaration
+--FILE--
+<?php
+namespace Exception {
+function foo() {
+  echo "ok\n";
+}
+}
+Exception::foo();
+--EXPECTF--
+ok
+
Index: Zend/tests/ns_042.phpt
===================================================================
RCS file: Zend/tests/ns_042.phpt
diff -N Zend/tests/ns_042.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Zend/tests/ns_042.phpt      20 Aug 2007 19:46:54 -0000
@@ -0,0 +1,15 @@
+--TEST--
+042: namespace with brackets, class declaration
+--FILE--
+<?php
+namespace Exception {
+class test {
+static function foo() {
+  echo "ok\n";
+}
+}
+}
+Exception::test::foo();
+--EXPECTF--
+ok
+
Index: Zend/tests/ns_043.phpt
===================================================================
RCS file: Zend/tests/ns_043.phpt
diff -N Zend/tests/ns_043.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Zend/tests/ns_043.phpt      20 Aug 2007 19:46:54 -0000
@@ -0,0 +1,20 @@
+--TEST--
+043: namespace with brackets, class declaration + function declaration
+--FILE--
+<?php
+namespace Exception {
+class test {
+static function foo() {
+  echo "ok\n";
+}
+}
+function foo() {
+  echo "ok\n";
+}
+}
+Exception::test::foo();
+Exception::foo();
+--EXPECTF--
+ok
+ok
+
Index: Zend/tests/ns_044.phpt
===================================================================
RCS file: Zend/tests/ns_044.phpt
diff -N Zend/tests/ns_044.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Zend/tests/ns_044.phpt      20 Aug 2007 19:46:54 -0000
@@ -0,0 +1,34 @@
+--TEST--
+044: namespace with brackets, two namespace declarations
+--FILE--
+<?php
+namespace Exception {
+class test {
+static function foo() {
+  echo "ok\n";
+}
+}
+function foo() {
+  echo "ok\n";
+}
+}
+Exception::test::foo();
+Exception::foo();
+namespace Second {
+class test {
+static function foo() {
+  echo "ok\n";
+}
+}
+function foo() {
+  echo "ok\n";
+}
+}
+Second::test::foo();
+Second::foo();
+--EXPECTF--
+ok
+ok
+ok
+ok
+
Index: Zend/tests/ns_045.phpt
===================================================================
RCS file: Zend/tests/ns_045.phpt
diff -N Zend/tests/ns_045.phpt
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Zend/tests/ns_045.phpt      20 Aug 2007 19:46:54 -0000
@@ -0,0 +1,31 @@
+--TEST--
+045: illegal nested namespace with brackets
+--FILE--
+<?php
+namespace Exception {
+class test {
+static function foo() {
+  echo "ok\n";
+}
+}
+function foo() {
+  echo "ok\n";
+}
+test::foo();
+foo();
+namespace Second {
+class test {
+static function foo() {
+  echo "ok\n";
+}
+}
+function foo() {
+  echo "ok\n";
+}
+}
+}
+Second::test::foo();
+Second::foo();
+--EXPECTF--
+Fatal error: Namespace cannot be declared twice (without brackets) or nested 
within brackets in %sns_045.php on line 13
+

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

Reply via email to