Hi, You probably have seen Derick's blog post http://www.derickrethans.nl/namespaces_in_php.php
It occurred to me today that there might be a simple, elegant solution to this problem. First, let's imagine someone writes this code: <?php include '/path/to/library/Closure.php'; use Fancy::Closure; $a = new Closure('for ($a = 1;$a<10;$a++) docrap();'); ?> Now, in PHP 5.4, we introduce an internal class "Closure" and the user's code suddenly breaks on the "use" statement because we check for an internal name conflict. Here's the kicker: why do we need to worry about a name conflict? This user's code was designed to work exclusively with Fancy::Closure, and doesn't care about any present or future internal classes that conflict! Also, because this is a compile-time alias that only affects the current script file, if we were to allow the above user's code to essentially override the internal Closure class, there is no possible harm because 1) the user explicitly imported Fancy::Closure 2) the user therefore never intends to use the internal ::Closure in this script In fact, the same thing is true for existing classnames. Why should we care if a user does this? <?php include '/path/to/my/date/lib.php'; use My::DateTime; $a = new DateTime('2006/04/05'); ?> The user is obviously intentionally creating a "DateTime" class, and doesn't care about the internal classname in this script. The attached patch against PHP_5_3 would fix the issue by eliminating the check for conflict with CG(class_table) in the global namespace for internal classes. It however preserves this check for userspace classes so that (for instance) php-src/tests/Zend/ns_030.phpt does not fail. The basic idea is that we do have control over the userspace classes we include, but have no control over the internal classes. A new test would also be needed: 066.php.inc: <?php namespace A; class B { function __construct(){echo __CLASS__;} } ?> --TEST-- 066: Name ambiguity (import name & internal class name) --FILE-- <?php include __DIR__ . '/066.php.inc'; use A::B as stdClass; new stdClass(); --EXPECT-- A::B Thanks, Greg
Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.647.2.27.2.41.2.68 diff -u -r1.647.2.27.2.41.2.68 zend_compile.c --- Zend/zend_compile.c 15 Jun 2008 18:27:37 -0000 1.647.2.27.2.41.2.68 +++ Zend/zend_compile.c 20 Jun 2008 15:47:41 -0000 @@ -4959,6 +4959,7 @@ char *lcname; zval *name, *ns, tmp; zend_bool warn = 0; + zend_class_entry **pce; if (!CG(current_import)) { CG(current_import) = emalloc(sizeof(HashTable)); @@ -5012,14 +5013,16 @@ 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)); - - 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)); + } else if (SUCCESS == zend_hash_find(CG(class_table), lcname, Z_STRLEN_P(name)+1, (void **)&pce)) { + if (pce[0]->type == ZEND_USER_CLASS) { + 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) {
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php