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
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php