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

Reply via email to