solving the namespace conflict issues between function/static method class constant/ns constant

From: Date: Sat, 20 Sep 2008 03:59:46 +0000
Subject: solving the namespace conflict issues between function/static method class constant/ns constant
Groups: php.internals 
Request: Send a blank email to internals+get-40569@lists.php.net to get a copy of this message
Hi all, There is a problem in the namespace implementation. This code demonstrates the issue: code.inc: <?php namespace foo; class test { const my = 1; static function bar(){} } namespace foo::test; const my = 2; function bar(){} ?> main.php: <?php include 'code.inc'; foo::test::bar(); // always calls namespace function call_user_func(array('foo::test', 'bar')); // the only way to call static method echo foo::test::my; // always 2 $a = new foo::test; echo $a::my; // the only way to access foo::test::my ?> There are 5 ways to solve this: 1) document it and hope no one uses it [this is the current strategy, minus the documentation part] 2) add a fatal error on conflicting names. http://pear.php.net/~greg/ns_method.func.conflict.patch.txt Unfortunately, this can only work for methods/functions, as namespace constants are actually defined at run-time, and so conflicts can't be detected until then, which does not provide any benefit (you want to catch this conflict at compile-time). 3) create a disambiguation method. http://pear.php.net/~greg/ns.func_const.patch.txt This introduces function:: and const:: as prefixes to disambiguate. <?php function::foo::test::bar(); // always calls namespace function foo::test::bar(); // always calls static method if defined, falls back to ns function if not const::foo::test::my; // namespace constant foo::test::my; // class constant ?> The drawback of this approach is that "foo::test::bar" will always look for class "foo::test", which means if autoload is defined, it will be called for all non-prefixed function calls. Unfortunately, the only other keyword for disambiguating would be "class::" as in "class::foo::test::bar()" but this is excessively confusing. 4) remove functions/constants from namespaces 5) a simply syntax change to namespaces, introducing a new concept: namespace element. A namespace element is a class, function or constant defined within a namespace declaration: <?php namespace foo; class bar {} // class element bar in namespace foo function bar(){} // function element bar in namespace foo const bar=1; // const element bar in namespace foo ?> This is similar to class elements: <?php class foo { function bar(){} // method element bar in class foo const bar=1; // constant element bar in class foo public $bar=1; // variable element bar in class foo } ?> Currently, this code: <?php namespace foo::bar; class buh{} ?> creates a class named "foo::bar::buh", essentially joining the namespace "foo::bar" and its class element "buh" with the separator "::". This turns out to be the root of the problem with the conflicts between class elements and namespace elements. The last patch introduces a new namespace element operator to delineate the boundary between namespace name and element name. For the patch, I recycled T_OBJECT_OPERATOR (->). current way: <?php foo::bar->test(); // namespace foo::bar, call to function element test() foo->bar::test(); // namespace foo, call to static method element test() in class element bar foo->myconst; // namespace foo constant myconst foo::myconst; // class foo constant myconst ?> The patch is at: http://pear.php.net/~greg/ns.element.patch.txt This is the most extensive change. The patch preserves :: as global element accessor (::strlen() calls strlen internal function, for instance). I'm happy to answer any other questions. So, these are the choices. I suggest we all take a rational look at the options, and understand the consequences of each, and make the best choice possible. Thanks, Greg

« previous php.internals (#40569) next »