7

The following throws an error stating Exception can not be redeclared.

namespace \NYTD\ReadingListBackend;

class Exception extends \Exception
{
}

However, removing the \ prefix in the namespace declaration does not:

namespace NYTD\ReadingListBackend;

I recently adopted PHP namespaces. My understanding is that namespaces prefixed with \ represent a fully qualified name.

So why can't I use the prefix in the namespace declaration? I can when referencing (e.g. new \NYTD\ReadingListBackend\Exception). Would appreciate a full explanation as I couldn't find anything in the docs.

Jason McCreary
  • 71,546
  • 23
  • 135
  • 174
  • In the docs they use the \ at beginning only to call it. To declare it they dont't use it. So it should be: namespace NYTD\ReadingListBackend; and when you want to access it, you only write NYTD\ReadingListBackend\Exception; – PKeidel Oct 26 '12 at 15:08
  • I think PHP expects `\NYTD\ReadingListBackend` to be a constant or something. Omit the initial `\` and you should be fine – Elias Van Ootegem Oct 26 '12 at 15:12
  • @PKeidel, can you supply a link. I must have missed that line of the docs. – Jason McCreary Oct 26 '12 at 15:13
  • @Elias Van Ootegem, I realize that. I'm trying to understand the internals of *why*. – Jason McCreary Oct 26 '12 at 15:14
  • http://php.net/manual/en/language.namespaces.definition.php – Gordon Oct 26 '12 at 15:15
  • @JasonMcCreary it doesnt say. I am just applying Occam's Razor, which means the likelihood of the manual showing the correct usage is higher than the theory that it is missing that you can apply the backslash. But you have a look at http://lxr.php.net/search?q=T_NAMESPACE&defs=&refs=&path=&hist=&project=PHP_TRUNK - the truth is in there. – Gordon Oct 26 '12 at 15:23
  • @Jason I only looked at the examples. E.g. [this](http://www.php.net/manual/en/language.namespaces.php#104136) or [this](http://php.net/manual/en/language.namespaces.definition.php) – PKeidel Oct 26 '12 at 15:25
  • @Gordon, understood. Honestly, I don't mean to be difficult. I realize the \ prefix in the namespace declaration *doesn't work*. I'm just trying to understand *why*. – Jason McCreary Oct 26 '12 at 15:37
  • @JasonMcCreary I didnt perceive you to be difficult at all. My C is just not good enough to explain "*why*" at the level you are likely looking for in an answer, hence the link to the source. – Gordon Oct 26 '12 at 15:39
  • @Gordon, the way I read the grammar, a prefix of `T_NS_SEPARATOR` is allowed. So the question becomes, why do the two namespace declarations parse differently… – Jason McCreary Oct 26 '12 at 15:56
  • The prefix *does not work* with curly brackets notation ([demo](http://codepad.viper-7.com/IJyVXN)). I'd say when this was implemented, it was not possible to throw a parse error in the case you outline because of the limited abilities of the PHP parser (or was too hard to create and then just dropped). – hakre Oct 26 '12 at 16:23
  • @hakre, thanks for the example. What does that mean as far as an answer? – Jason McCreary Oct 26 '12 at 16:52
  • No, it does not answer the question at all, it adds more question marks I'd say ;) Interesting find by the way! – hakre Oct 26 '12 at 16:53

3 Answers3

8

As mentioned in the other answers the namespace declaration always takes a fully-qualified name and as such a trailing \ would be redundant and is not allowed.

Writing namespace \NYTD\ReadingListBackend { ... } will lead to a proper parse error.

When using the semicolon notation namespace \NYTD\ReadingListBackend; on the other hand it is interpreted as namespace\NYTD\ReadingListBackend;, which is an access to the constant NYTD\ReadingListBackend (the namespace keyword here resolves to the currently active namespace, which in your case is the global one).

So your code does not declare any namespace (it is global) and just tries to access a constant. That's why you end up redefining Exception.

By the way, the reason why the undefined constant access does not throw a fatal error is class hoisting. Your class declaration is evaluated first, so PHP never actually reaches the constant access (even though it comes first in code).

NikiC
  • 100,734
  • 37
  • 191
  • 225
  • +1 Excellent explanation. But if this is true, then that would mean the grammar allows for spaces in namespaces. Which seems wrong. – Jason McCreary Oct 26 '12 at 20:47
  • @JasonMcCreary Correct. PHP ignores all whitespace and comments. It does not care whether you write `namespace\Foo\Bar`, `namespace \ Foo \ Bar` or `namespace /* a */ \ /* very */ Foo /* odd */ \ /* comment */ Bar` ;) – NikiC Oct 26 '12 at 20:56
  • Yes, but it should not ignore whitespace in this case. It doesn't for `$ var`. Nonetheless, I verified your answer by using `echo __NAMESPACE__;` after the declaration. This is indeed what happens with the \ prefix. – Jason McCreary Oct 26 '12 at 20:58
2

So why can't I use the prefix in the namespace declaration?

By definition when you declare a namespace name it is already fully qualified.

But inside a namespace'd part of the code, if you need to specify a fully qualified class name (FQCN) you need the prefix to signal PHP that the class name is a FQCN.

What is irritating here is that PHP does not already error out at parse time in your example. I can not tell you why.

namespace \NYTD\ReadingListBackend;
          ^- this seems wrong but no parse error

However PHP does the error with the curly notation (multiple namespaces in one file):

namespace \NYTD\ReadingListBackend {}
                                   ^- parse error in this line

But for your question, I think it's worth to differ between the namespace-name and the class-name.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • +1, best answer so far *by definition when you declare a namespace name it is already fully qualified.* :) – Jason McCreary Oct 26 '12 at 17:03
  • Yes, if you look into http://php.net/language.namespaces.nested you can see that the separator is used only between the namespace names. In http://php.net/language.namespaces.definition no separator is used at all. – hakre Oct 26 '12 at 17:10
  • I have read through the docs several times. Without a parse error, I was trying to find something *explicit* about using the separator as a prefix. The fact that it runs, but is interpreted differently ultimately lead to my confusion. – Jason McCreary Oct 26 '12 at 17:16
  • Yes I can understand the confusion. However, nowhere in the documentation of the `namespace` keyword it is said to use the namespace separator in front of the first name. There is nothing to separate at that place. I think I'll file a bug report. – hakre Oct 26 '12 at 17:21
  • Can neither confirm nor deny. I was reluctant to say *bug*. However, after reviewing the grammar, there may be one. Especially given the inconsistency when using namespace block syntax (i.e. `{`). – Jason McCreary Oct 26 '12 at 17:23
1

A \ prefix means 'root' or something like that. It makes a fully qualified namespace (/Foo/Bar) of a qualified namespace (Foo/Bar). This is only useful when using namespaces, not when declaring namespaces. For instance:

namespace Foo

class Bar {
    // ...
}

namespace Bar\Baz;

$b = new Bar(); // look for Bar\Baz\Bar()
$b = new Foo\Bar(); // look for Bar\Baz\Foo\Bar()
$b = new \Foo\Bar(); // look for Foo\Bar() (the right one)

It isn't usefull when declaring a namespace, because you always declare a namespace from the global ('root') namespace:

namespace Foo; // the \Foo namespace
// ...
namespace Bar; // the \Bar namespace, not the \Foo\Bar namespace
// ...
namespace Foo\Bar; // the \Foo\Bar namespace

Because every namespace declaration is sort of 'fully qualified' PHP doesn't want a \ in front of the namespace and gives you an error.

Dan Blows
  • 20,846
  • 10
  • 65
  • 96
Wouter J
  • 41,455
  • 15
  • 107
  • 112
  • I read about [namespace resolution](http://php.net/manual/en/language.namespaces.rules.php). I would expect that using this prefix would either result in a syntax error or work as a *fully qualified namespace*. Not run with a different result… – Jason McCreary Oct 26 '12 at 15:39