# simple solution to another namespace conundrum?

- Thread: https://externals.io/message/38472
- Original archive: https://news-web.php.net/php.internals/38472
- Started by Gregory Beaver on 2008-06-20T15:50:24+00:00
- Messages: 16
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #38472 — Gregory Beaver — 2008-06-20T15:50:24+00:00

URL: https://externals.io/message/38472#38472

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

---

## #38476 — Dmitry Stogov — 2008-06-20T16:10:41+00:00

URL: https://externals.io/message/38472#38476 · In reply to: #38472

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.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

---

## #38481 — Gregory Beaver — 2008-06-20T16:42:35+00:00

URL: https://externals.io/message/38472#38481 · In reply to: #38476

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

---

## #38499 — Jessie Hernandez — 2008-06-21T19:29:26+00:00

URL: https://externals.io/message/38472#38499 · In reply to: #38472

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.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

---

## #38500 — Jessie Hernandez — 2008-06-21T19:29:48+00:00

URL: https://externals.io/message/38472#38500 · In reply to: #38472

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.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

---

## #38501 — Gregory Beaver — 2008-06-21T20:24:19+00:00

URL: https://externals.io/message/38472#38501 · In reply to: #38499

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

---

## #38579 — Derick Rethans — 2008-06-24T14:36:12+00:00

URL: https://externals.io/message/38472#38579 · In reply to: #38472

> 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

---

## #38580 — Alexey Zakhlestin — 2008-06-24T14:47:48+00:00

URL: https://externals.io/message/38472#38580 · In reply to: #38579

> 
>
> > […]
>
> 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/

---

## #38582 — Derick Rethans — 2008-06-24T14:52:50+00:00

URL: https://externals.io/message/38472#38582 · In reply to: #38580

> 
> > […]
> 
> 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

---

## #38583 — Rasmus Lerdorf — 2008-06-24T15:04:40+00:00

URL: https://externals.io/message/38472#38583 · In reply to: #38582

Derick Rethans wrote:
> 
> 
> > […]
> 
> 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

---

## #38585 — Lukas Kahwe Smith — 2008-06-24T15:38:19+00:00

URL: https://externals.io/message/38472#38585 · In reply to: #38582

> 
>
> > […]
>
> 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

---

## #38586 — James Dempster — 2008-06-24T16:06:16+00:00

URL: https://externals.io/message/38472#38586 · In reply to: #38585

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:

>
> 
>
>  
> > […]
>
>
> 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

---

## #38617 — Greg Beaver — 2008-06-25T19:42:29+00:00

URL: https://externals.io/message/38472#38617 · In reply to: #38579

Derick Rethans wrote:
> 
> 
> > […]
> 
> 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

---

## #38624 — Jochem Maas — 2008-06-26T03:59:19+00:00

URL: https://externals.io/message/38472#38624 · In reply to: #38617

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

---

## #38627 — Derick Rethans — 2008-06-26T07:38:16+00:00

URL: https://externals.io/message/38472#38627 · In reply to: #38583

> Derick Rethans wrote:
> > […]
> 
> 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

---

## #38642 — James Dempster — 2008-06-26T18:07:49+00:00

URL: https://externals.io/message/38472#38642 · In reply to: #38627

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



> 
>
> > […]
>
> 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
