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
- the user explicitly imported Fancy::Closure
- 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
Looks fine, but probably we should emit error only if class declared in
the same source file.
Thanks. Dmitry.
Gregory Beaver wrote:
Hi,
You probably have seen Derick's blog post
http://www.derickrethans.nl/namespaces_in_php.phpIt 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
- the user explicitly imported Fancy::Closure
- the user therefore never intends to use the internal ::Closure in
this scriptIn 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::BThanks,
Greg
Dmitry Stogov wrote:
Looks fine, but probably we should emit error only if class declared in
the same source file.Thanks. Dmitry.
Great, didn't realize how easy this would be. Attached patch does this,
but requires another test:
067.php.inc:
<?php
class B
{
function __construct(){echo CLASS;}
}
?>
--TEST--
067: Name ambiguity (import name & userspace class name in another file)
--FILE--
<?php
include DIR . '/066.php.inc';
include DIR . '/067.php.inc';
use A::B;
new B();
--EXPECT--
A::B
I can't express how excited I am about this patch - it fixes the biggest
single problem with the "use" statement and negates the need for any
weird stuff like "namespace user;" as proposed. Now, once we fix
resolution rules, namespaces will be stellar.
Greg
Hi Greg,
How is this different from my original proposal
(http://news.php.net/php.internals/34097,
http://news.php.net/php.internals/34097)?
--
Jessie Hernandez
Zend Certified Engineer (http://zend.com/zce.php?c=ZEND006359&r=222727282)
Gregory Beaver wrote:
Hi,
You probably have seen Derick's blog post
http://www.derickrethans.nl/namespaces_in_php.phpIt 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
- the user explicitly imported Fancy::Closure
- the user therefore never intends to use the internal ::Closure in
this scriptIn 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::BThanks,
Greg
Jessie Hernandez wrote:
Hi Greg,
How is this different from my original proposal
(http://news.php.net/php.internals/34097,
http://news.php.net/php.internals/34097)?
The patch committed only affects non-namespaced code, your proposal
affected all code. In other words, this always works:
<?php
namespace Foo;
include 'blah.php';
use Blah::Closure;
$a = new Closure();
?>
whereas this:
<?php
include 'blah.php';
use Blah::Closure;
$a = new Closure();
?>
had the potential to fail with fatal error without code change on
upgrade to a newer PHP version that creates the "Closure" class. The
committed patch addresses only this shortcoming, and changes nothing else.
In other words, this:
<?php
namespace Foo;
$a = new Exception('hi');
var_dump(get_class($a));
?>
still prints "Exception" and not "Foo::Exception".
Additionally, unlike your proposal, all existing namespace tests still
pass with the behavior change. 2 new tests were added, 1 to test the
relaxed behavior, and 1 to test that this next example is a fatal error
because definition of Foo::Closure is in the same file as the "use
Blah::Closure":
<?php
namespace Foo;
include 'blah.php';
class Closure{}
use Blah::Closure; // unqualified name "Closure" is already taken, fatal
error.
?>
Greg
Hi Greg,
How is this different from my original proposal
(http://news.php.net/php.internals/34097,
http://news.php.net/php.internals/36822)?
--
Jessie Hernandez
Zend Certified Engineer (http://zend.com/zce.php?c=ZEND006359&r=222727282)
Gregory Beaver wrote:
Hi,
You probably have seen Derick's blog post
http://www.derickrethans.nl/namespaces_in_php.phpIt 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
- the user explicitly imported Fancy::Closure
- the user therefore never intends to use the internal ::Closure in
this scriptIn 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::BThanks,
Greg
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.
I am not so sure this is a good idea. I mean, for the developer that
writes the code it's obvious that his version of DateTime is used. But
for a second developer to come back later this could be a great WTF
factor a few years down the road - wondering why the DateTime
documentation on php.net doesn't match with what the class does.
regards,
Derick
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.I am not so sure this is a good idea. I mean, for the developer that
writes the code it's obvious that his version of DateTime is used. But
for a second developer to come back later this could be a great WTF
factor a few years down the road - wondering why the DateTime
documentation on php.net doesn't match with what the class does.
it won't be a serious 'wtf', as on the top of the file, there would be
some kind of
use MySuperLibrary::DateTime;
--
Alexey Zakhlestin
http://blog.milkfarmsoft.com/
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.I am not so sure this is a good idea. I mean, for the developer that
writes the code it's obvious that his version of DateTime is used. But
for a second developer to come back later this could be a great WTF
factor a few years down the road - wondering why the DateTime
documentation on php.net doesn't match with what the class does.it won't be a serious 'wtf', as on the top of the file, there would be
some kind of
use MySuperLibrary::DateTime;
I know, but 400 lines down in the code you can't really see that. This
addition might fix the immediate issue - but it doesn't make life easier
for the developers that have to maintain the code. Even less if they're
not aware that stuff is namespaced.
regards,
Derick
Derick Rethans wrote:
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.
I am not so sure this is a good idea. I mean, for the developer that
writes the code it's obvious that his version of DateTime is used. But
for a second developer to come back later this could be a great WTF
factor a few years down the road - wondering why the DateTime
documentation on php.net doesn't match with what the class does.
it won't be a serious 'wtf', as on the top of the file, there would be
some kind of
use MySuperLibrary::DateTime;I know, but 400 lines down in the code you can't really see that. This
addition might fix the immediate issue - but it doesn't make life easier
for the developers that have to maintain the code. Even less if they're
not aware that stuff is namespaced.
If we don't allow it to work this way, then I really don't see the point
in namespaces at all, which I assume is the point you are trying to
make. But, assuming at this point that we do want namespaces, then we
have to make them work, and by its very nature namespacing involves code
obfuscation. With or without this change, having the same userspace
functions in different namespaces provides the same level of code
obfuscation where a line of code read in isolation is impossible to
resolve without looking at its namespace context.
-Rasmus
Derick Rethans wrote:
it won't be a serious 'wtf', as on the top of the file, there
would be some kind of use MySuperLibrary::DateTime;I know, but 400 lines down in the code you can't really see that.
This addition might fix the immediate issue - but it doesn't make
life easier for the developers that have to maintain the code. Even
less if they're not aware that stuff is namespaced.If we don't allow it to work this way, then I really don't see the
point in namespaces at all, which I assume is the point you are trying
to make.
Actually, the point that I was trying to make is that we instead of
encouraging this confusion, we should put somewhere in our userland
nameing guidelines that you still would need to provide a prefix to your
(aliased) classnames in order to prevent confusion. But that then
seriously means I see no real good reason still why people want
namespaces with confusing resolving rules (concerning static methods
like Greg points out).
regards,
Derick
--
Derick Rethans
http://derickrethans.nl | http://ezcomponents.org | http://xdebug.org
I would agree, they seem to cause more problems and pollution than it would
solve.
I like the idea behind namespaces but what I've seen of the current
implementations I would rather do without.
Unfortunately I don't have any ideas or solutions to the problems.
/James Dempster
Derick Rethans wrote:
it won't be a serious 'wtf', as on the top of the file, there
would be some kind of use MySuperLibrary::DateTime;I know, but 400 lines down in the code you can't really see that.
This addition might fix the immediate issue - but it doesn't make
life easier for the developers that have to maintain the code. Even
less if they're not aware that stuff is namespaced.If we don't allow it to work this way, then I really don't see the
point in namespaces at all, which I assume is the point you are trying
to make.Actually, the point that I was trying to make is that we instead of
encouraging this confusion, we should put somewhere in our userland
nameing guidelines that you still would need to provide a prefix to your
(aliased) classnames in order to prevent confusion. But that then
seriously means I see no real good reason still why people want
namespaces with confusing resolving rules (concerning static methods
like Greg points out).regards,
Derick--
Derick Rethans
http://derickrethans.nl | http://ezcomponents.org | http://xdebug.org
On Tue, Jun 24, 2008 at 6:36 PM, Derick Rethans derick@php.net
wrote: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.I am not so sure this is a good idea. I mean, for the developer that
writes the code it's obvious that his version of DateTime is used.
But
for a second developer to come back later this could be a great WTF
factor a few years down the road - wondering why the DateTime
documentation on php.net doesn't match with what the class does.it won't be a serious 'wtf', as on the top of the file, there would
be
some kind of
use MySuperLibrary::DateTime;I know, but 400 lines down in the code you can't really see that. This
addition might fix the immediate issue - but it doesn't make life
easier
for the developers that have to maintain the code. Even less if
they're
not aware that stuff is namespaced.
I think this is the name of the game. If you want namespace magic,
then you have to live with it. I am sure that editors and IDE's can
easily be extended the provide some assistance here. But it does of
course means that when people share code, they can no longer rely that
some namespace kung-fu will not break seemingly innocent code.
As such I am +1 for Greg's change.
regards,
Lukas Kahwe Smith
mls@pooteeweet.org
I find it interesting that we could quite possibly get just as many clashes
with namespaced code.
Of course it comes down to how well the developer implements there code.
It's almost like namespace is just a method of aliasing long class names.
On Tue, Jun 24, 2008 at 4:38 PM, Lukas Kahwe Smith mls@pooteeweet.org
wrote:
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.I am not so sure this is a good idea. I mean, for the developer that
writes the code it's obvious that his version of DateTime is used. But
for a second developer to come back later this could be a great WTF
factor a few years down the road - wondering why the DateTime
documentation on php.net doesn't match with what the class does.it won't be a serious 'wtf', as on the top of the file, there would be
some kind of
use MySuperLibrary::DateTime;I know, but 400 lines down in the code you can't really see that. This
addition might fix the immediate issue - but it doesn't make life easier
for the developers that have to maintain the code. Even less if they're
not aware that stuff is namespaced.I think this is the name of the game. If you want namespace magic, then you
have to live with it. I am sure that editors and IDE's can easily be
extended the provide some assistance here. But it does of course means that
when people share code, they can no longer rely that some namespace kung-fu
will not break seemingly innocent code.As such I am +1 for Greg's change.
regards,
Lukas Kahwe Smith
mls@pooteeweet.org
Derick Rethans wrote:
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.I am not so sure this is a good idea. I mean, for the developer that
writes the code it's obvious that his version of DateTime is used. But
for a second developer to come back later this could be a great WTF
factor a few years down the road - wondering why the DateTime
documentation on php.net doesn't match with what the class does.
Hi Derick,
This is (as Rasmus points out) a hazard of using namespaces, but it need
not be a large hazard. I've said this before, but it would be wise to
implement a namespace-expansion similar to whitespace-stripping option
in php, so that one can convert use statements to namespace names. Of
course, a PHP script to do this would be about 25 lines long, so that is
an option too, but I would guarantee that if you're finding this wtf to
be a problem, there are going to be more problems in the script than
just use statements that alias to internal classnames.
To be more direct - the "use" statement only applies to the current
file, which makes debugging this situation much easier.
The real WTF comes into play when you have a static method that resolves
to the same name as a namespaced function, something that absolutely
must be worked out prior to PHP 5.3's release. I know a few ideas are
percolating about on this one from the people I've talked to on and
off-list, I am looking forward to the ultimate resolution.
Greg
Greg Beaver schreef:
Derick Rethans wrote:
..
The real WTF comes into play when you have a static method that resolves
to the same name as a namespaced function, something that absolutely
must be worked out prior to PHP 5.3's release. I know a few ideas are
percolating about on this one from the people I've talked to on and
off-list, I am looking forward to the ultimate resolution.
is it just me or does that come down to choosing the wrong namespace delimiter?
anything other than '::' would allow both the engine and user code
(e.g. __autoload()) to differentiate when a namespace is used or not, no?
Greg