Attached is a patch implementing my proposal.
Basically, when inside a namespace, you must reference global classes
using ::globalName or by having a "use ::globalName" statement. This
allows classes inside namespaces to have the same name as internal ones
without the need of explicitly "use"-ing them (and prevents clashes with
new internal classes in the future). This only applies to classes,
functions/constants will still follow the current rules, since
__autoload does not apply to them (meaning you won't have to do things
like ::strlen just because you're inside a namespace).
Also, no errors are generated when using a class with the same name as
an internal class, BUT there is an error if you import/alias a class
with the same name as a global (non-internal) class. The reason for this
is that the user has control of which global classes they're including,
while the same might not be true of internal classes.
Some tests had to be modified to support the patch, and there might be a
need for additional tests to be included, but at least you can all try
out the patch and see how you feel about these new rules.
Please look at the patch, try it out, and let me know what you think
about it or if there's anything that can be improved. Thanks.
Regards,
Jessie Hernandez
Zend Certified Engineer (http://zend.com/zce.php?c=ZEND006359&r=222727282)
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.647.2.27.2.41.2.31
diff -u -r1.647.2.27.2.41.2.31 zend_compile.c
--- Zend/zend_compile.c 13 Dec 2007 10:02:03 -0000 1.647.2.27.2.41.2.31
+++ Zend/zend_compile.c 19 Dec 2007 01:19:06 -0000
@@ -4781,6 +4781,7 @@
{
char *lcname;
zval *name, *ns, tmp;
+ zend_class_entry **pce;
zend_bool warn = 0;
if (!CG(current_import)) {
@@ -4835,14 +4836,18 @@
efree(tmp);
}
efree(ns_name);
- } else if (zend_hash_exists(CG(class_table), lcname, Z_STRLEN_P(name)+1)) {
- char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns));
+ } else if (zend_hash_find(CG(class_table), lcname, Z_STRLEN_P(name)+1, (void **) &pce) == SUCCESS) {
+ zend_class_entry *ce = *pce;
- if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) ||
- memcmp(tmp, lcname, Z_STRLEN_P(ns))) {
- zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name));
+ if ((ce->type & ZEND_INTERNAL_CLASS) == 0) {
+ char *tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns));
+
+ if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) ||
+ memcmp(tmp, lcname, Z_STRLEN_P(ns))) {
+ zend_error(E_COMPILE_ERROR, "Cannot use %s as %s because the name is already in use", Z_STRVAL_P(ns), Z_STRVAL_P(name));
+ }
+ efree(tmp);
}
- efree(tmp);
}
if (zend_hash_add(CG(current_import), lcname, Z_STRLEN_P(name)+1, &ns, sizeof(zval*), NULL) != SUCCESS) {
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.331.2.20.2.24.2.14
diff -u -r1.331.2.20.2.24.2.14 zend_execute_API.c
--- Zend/zend_execute_API.c 7 Dec 2007 17:11:23 -0000 1.331.2.20.2.24.2.14
+++ Zend/zend_execute_API.c 19 Dec 2007 01:19:08 -0000
@@ -1556,7 +1556,6 @@
{
zend_class_entry **pce;
int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0;
- int rt_ns_check = (fetch_type & ZEND_FETCH_CLASS_RT_NS_CHECK) ? 1 : 0;
int silent = (fetch_type & ZEND_FETCH_CLASS_SILENT) != 0;
fetch_type &= ZEND_FETCH_CLASS_MASK;
@@ -1590,36 +1589,12 @@
break;
}
- if (zend_lookup_class_ex(class_name, class_name_len, (!rt_ns_check & use_autoload), &pce TSRMLS_CC) == FAILURE) {
- if (rt_ns_check) {
- /* Check if we have internal class with the same name */
- char *php_name;
- uint php_name_len;
-
- php_name = zend_memrchr(class_name, ':', class_name_len);
- if (php_name) {
- php_name++;
- php_name_len = class_name_len - (php_name - class_name);
- php_name = zend_str_tolower_dup(php_name, php_name_len);
- if (zend_hash_find(EG(class_table), php_name, php_name_len + 1, (void **) &pce) == SUCCESS &&
- (*pce)->type == ZEND_INTERNAL_CLASS
- ) {
- efree(php_name);
- return *pce;
- }
- efree(php_name);
- }
- }
- if (use_autoload) {
- if (rt_ns_check && zend_lookup_class_ex(class_name, class_name_len, 1, &pce TSRMLS_CC) == SUCCESS) {
- return *pce;
- }
- if (!silent) {
- if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) {
- zend_error(E_ERROR, "Interface '%s' not found", class_name);
- } else {
- zend_error(E_ERROR, "Class '%s' not found", class_name);
- }
+ if (zend_lookup_class_ex(class_name, class_name_len, use_autoload, &pce TSRMLS_CC) == FAILURE) {
+ if (use_autoload && !silent) {
+ if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) {
+ zend_error(E_ERROR, "Interface '%s' not found", class_name);
+ } else {
+ zend_error(E_ERROR, "Class '%s' not found", class_name);
}
}
return NULL;
Index: Zend/tests/bug42802.phpt
===================================================================
RCS file: /repository/ZendEngine2/tests/bug42802.phpt,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 bug42802.phpt
--- Zend/tests/bug42802.phpt 1 Oct 2007 10:37:14 -0000 1.1.2.1
+++ Zend/tests/bug42802.phpt 19 Dec 2007 01:19:22 -0000
@@ -4,6 +4,8 @@
<?php
namespace foo;
+use ::Exception;
+
class bar {
}
@@ -42,4 +44,4 @@
ok
ok
-Catchable fatal error: Argument 1 passed to foo::test6() must be an instance of bar, instance of foo::bar given, called in %sbug42802.php on line 23
+Catchable fatal error: Argument 1 passed to foo::test6() must be an instance of bar, instance of foo::bar given, called in %sbug42802.php on line 36%s
Index: Zend/tests/bug43332_1.phpt
===================================================================
RCS file: /repository/ZendEngine2/tests/bug43332_1.phpt,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 bug43332_1.phpt
--- Zend/tests/bug43332_1.phpt 3 Dec 2007 14:15:43 -0000 1.1.2.1
+++ Zend/tests/bug43332_1.phpt 19 Dec 2007 01:19:22 -0000
@@ -4,6 +4,8 @@
<?php
namespace foobar;
+use ::stdClass;
+
class foo {
public function bar(self $a) { }
}
@@ -12,4 +14,4 @@
$foo->bar($foo); // Ok!
$foo->bar(new stdclass); // Error, ok!
--EXPECTF--
-Catchable fatal error: Argument 1 passed to foobar::foo::bar() must be an instance of foobar::foo, instance of stdClass given, called in %sbug43332_1.php on line 10 and defined in %sbug43332_1.php on line 5
+Catchable fatal error: Argument 1 passed to foobar::foo::bar() must be an instance of foobar::foo, instance of stdClass given, called in %sbug43332_1.php on line 12 and defined in %sbug43332_1.php on line 7
Index: Zend/tests/ns_004.phpt
===================================================================
RCS file: /repository/ZendEngine2/tests/ns_004.phpt,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 ns_004.phpt
--- Zend/tests/ns_004.phpt 28 Sep 2007 19:52:52 -0000 1.1.2.2
+++ Zend/tests/ns_004.phpt 19 Dec 2007 01:19:23 -0000
@@ -4,6 +4,8 @@
<?php
namespace test::ns1;
+use ::Exception;
+
echo get_class(new Exception()),"\n";
--EXPECT--
Exception
Index: Zend/tests/ns_038.phpt
===================================================================
RCS file: /repository/ZendEngine2/tests/ns_038.phpt,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 ns_038.phpt
--- Zend/tests/ns_038.phpt 28 Sep 2007 19:52:52 -0000 1.1.2.2
+++ Zend/tests/ns_038.phpt 19 Dec 2007 01:19:24 -0000
@@ -11,5 +11,5 @@
--EXPECTF--
ok
-Fatal error: Call to undefined method Exception::bar() in %sns_038.php on line 7
+Fatal error: Class 'Exception::Exception' not found in %sns_038.php on line 7
Index: Zend/tests/ns_055.phpt
===================================================================
RCS file: /repository/ZendEngine2/tests/ns_055.phpt,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 ns_055.phpt
--- Zend/tests/ns_055.phpt 9 Nov 2007 13:34:58 -0000 1.1.2.1
+++ Zend/tests/ns_055.phpt 19 Dec 2007 01:19:24 -0000
@@ -4,6 +4,8 @@
<?php
namespace test::ns1;
+use ::Exception;
+
class Foo {
function test1(Foo $x) {
echo "ok\n";
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php