Hi,
Stas and company decided that they wanted namespaces to have two legal
syntax choices:
- single namespace per file:
<?php
namespace foo;
...
?>
- multiple namespaces per file:
<?php
namespace foo1 {
}
namespace foo2 {
}
?>
I've implemented these two syntax options in a patch found at
http://pear.php.net/~greg/bracketed.patch.txt based on earlier work of
Dmitry Stogov.
It turns out there are some tricky details to work out, especially with
regard to importing via use statements. If we just allow global,
un-namespaced code, for instance, we could end up with this mess:
<?php
use blah\blah;
$f = new blah;
namespace one {
use foo\bar as blah;
$a = new blah;
}
// what is this?
blah::hi();
?>
Technically, you could argue that blah::hi() should resolve to
blah\blah::hi(), but it is very difficult to track and figure out what
"blah" means by eye. Thus, in the patch I implemented, if bracketed
namespace declarations exist, global use statements are not allowed, but
must exist within namespace ns {} brackets.
This creates a problem - how do you combine namespaced and unnamespaced
code? To solve this, I introduced the oft-suggested "namespace {}"
syntax for un-namespaced code. Thus, the above script would become:
<?php
namespace {
use blah\blah;
$f = new blah;
}
namespace one {
use foo\bar as blah;
$a = new blah;
}
namespace {
use blah\blah;
blah::hi();
}
?>
Another important point is that imports specified by the "use" statement
disappear when we exit a namespace block. This way, it is very easy to
combine un-namespaced code that uses namespaces, and namespaced code.
Also very important to note is that the "namespace {}" syntax is
optional for any code that does not import other things via the "use"
statement - its sole purpose is to provide a clear visual and logical
wrapper within which imports occur.
Thus, this is also legal:
<?php
namespace newly\coded\stuff {
class mine { ... }
}
// old stuff here
class PEAR { ... }
?>
Lastly, if global code does make use of namespaces, but does not import
anything, it can also happily co-exist with bracketed namespace code:
<?php
namespace ns {
class mine { ... }
}
$a = new ns\mine;
// and so on
?>
Thanks,
Greg
<?php
use blah\blah;$f = new blah;
namespace one {
use foo\bar as blah;
$a = new blah;
}// what is this?
blah::hi();
?>Technically, you could argue that blah::hi() should resolve to
blah\blah::hi(), but it is very difficult to track and figure out what
"blah" means by eye. Thus, in the patch I implemented, if bracketed
namespace declarations exist, global use statements are not allowed, but
must exist within namespace ns {} brackets.This creates a problem - how do you combine namespaced and unnamespaced
code? To solve this, I introduced the oft-suggested "namespace {}"
...
Well, here's a cheesy mod of your example:
<?php
$f = 10;
function one() {
$f = 20;
}
echo $f; // what is this? 10 ;)
?>
I guess it's clear that code below or above a namespace is in the same
global namespace, so "use blah\blah" will apply ot "blah::hi();".
However, we do also need your suggestion: namespace [nothing] { ... } since
one of the major design goals of the {} syntax variation was to allow people
to merge multiple files for deployment. Something which several frameworks
already do.
When we merge two files with "use" clauses, we need a way to provide "blank
namespace" scope so the "use" applies only to the relevant part of the code.
We can't avoid your code example above either, since by default we don't
require every piece of code to be in a namespace. If we allow {} scoping,
it'll be awkward to suddenly require the remaining global code to be put in
an explicit scope too, and people will be confused.
Hence a solution that seems most natural to me, and covers all use cases is
the following (where the scope # tells you where the "use" declarations
apply):
<?php
// global, scope 1
namespace { // global, scope 2 }
// global, scope 1
namespace { // global, scope 3 }
// global, scope 1
namespace foo\bar { // foo\bar, scope 4 }
// global, scope 1
?
Stan Vassilev | FM wrote:
<?php
// global, scope 1namespace { // global, scope 2 }
// global, scope 1
namespace { // global, scope 3 }
// global, scope 1
namespace foo\bar { // foo\bar, scope 4 }
// global, scope 1
?>
I am afraid I must shed my generally congenial public nature to express
a strong opinion:
This is a horribly complex idea Stan. PHP's implementation of
namespaces do not define scope. Once we open that Pandora's box, there
is no turning back.
Big time -1 from me.
Remember, the patch I'm proposing would only be necessary for people
using un-namespaced code combined with namespaced code (already a bad
idea) and scattering "use" statements throughout the global code.
Also, the only supported use case behind allowing multiple namespaces
per file is to allow people to mash pre-existing separate PHP files
together, and have them still compile. Requiring brackets is designed
to make it more readable, and the "use" restriction furthers that goal.
I would have implemented this requiring all code to be encased in
namespace {} or namespace nsname {}, but that turned out to be virtually
impossible in the parser because of the need to also allow "declare"
statements outside namespace declarations
Thanks,
Greg
Hi,
Ok so I had a quick chat with greg and reread his proposal and it's actually
a sound proposal.
My original concern was that if we don't implement proper subset of
"namespace scopes" we'll have difficulty extending PHP in the future to
support function-local use declarations etc.
However Greg's proposal is in fact a strict subset of scopes, which could be
extended in the future in a backcompat nature.
It also covers all use cases by the community, so I'm "+1", if anyone is
counting that is. Sorry for the noise :)
Regards,
Stan Vassilev
Hey Greg,
Remember, the patch I'm proposing would only be necessary for people
using un-namespaced code combined with namespaced code (already a bad
idea) and scattering "use" statements throughout the global code.
If it's 'already a bad idea', why support it?
Also, the only supported use case behind allowing multiple namespaces
per file is to allow people to mash pre-existing separate PHP files
together, and have them still compile. Requiring brackets is designed
to make it more readable, and the "use" restriction furthers that goal.
This part makes sense.
- Steph
Steph Fox wrote:
Hey Greg,
Remember, the patch I'm proposing would only be necessary for people
using un-namespaced code combined with namespaced code (already a bad
idea) and scattering "use" statements throughout the global code.If it's 'already a bad idea', why support it?
Many people want this support, and it is only a bad idea if the code is
designed this way. If you are simply combining several files together,
it is a necessary feature.
Greg
Sorry for the second email, I just forgot to mention something regarding how
use statements apply from global scope to namespace x {}.
The best way regarding realworld usage and existing state of the art would
be to take into account the use statements in the scope above and apply the
use statements inside the scope after them.
So if I write this:
<?php
use A;
use B;
namespace {
use C;
}
?>
In the namespace, it's the same as if I wrote use A, B, C in that order
explicitly. Implemented this way, in a future version of PHP we could allow
this typical scenario (which I suspect won't work with this patch?):
<?php
use A;
function foo() {
use B; // use A applies implicitly, use B applied only for the scope of
the function
...code...
}
?>
Which code above is in fact a sugared version of what is actually happening:
<?php
use A;
function foo() { namespace {
use B; // use A applies implicitly, use B applied only for the scope
of the namespace scope
...code...
} }
?>
The above significantly helps with larger function/class libraries in a
single file, as you can make your use statements more local (typically you
will use certain classes globally, and most locally in a function/method),
and is supported by most modern languages that handle namespaces.
Regards, Stan Vassilev
Hey there!
Why don't you try an implementation as:
namespace foo;
(contents xyz)
namespace foob;
(contents xyz of as second called namespace)
Wouldn't it be easier to make such an application tree instead of using the
normal bracket-like opening?
Your,
(c) Kenan Sulayman
Freelance Designer and Programmer
Life's Live Poetry
Hello Gregory,
Friday, November 7, 2008, 10:14:50 PM, you wrote:
Hi,
Stas and company decided that they wanted namespaces to have two legal
syntax choices:
- single namespace per file:
<?php
namespace foo;
...
?>>
- multiple namespaces per file:
<?php
namespace foo1 {
}
namespace foo2 {
}
?>>
I've implemented these two syntax options in a patch found at
http://pear.php.net/~greg/bracketed.patch.txt based on earlier work of
Dmitry Stogov.
It turns out there are some tricky details to work out, especially with
regard to importing via use statements. If we just allow global,
un-namespaced code, for instance, we could end up with this mess:
For practical reasons outlined by you just again, we already decided not to
allow global code after any namespace declaration. That is a namespace can
only be followed by another namespace. So the rest of this analysis is
irrelevant.
marcus
<?php
use blah\blah;
$f = new blah;
namespace one {
use foo\bar as blah;
$a = new blah;
}
// what is this?
blah::hi();
?>>
Technically, you could argue that blah::hi() should resolve to
blah\blah::hi(), but it is very difficult to track and figure out what
"blah" means by eye. Thus, in the patch I implemented, if bracketed
namespace declarations exist, global use statements are not allowed, but
must exist within namespace ns {} brackets.
This creates a problem - how do you combine namespaced and unnamespaced
code? To solve this, I introduced the oft-suggested "namespace {}"
syntax for un-namespaced code. Thus, the above script would become:
<?php
namespace {
use blah\blah;
$f = new blah;
}
namespace one {
use foo\bar as blah;
$a = new blah;
}
namespace {
use blah\blah;
blah::hi();
}
?>>
Another important point is that imports specified by the "use" statement
disappear when we exit a namespace block. This way, it is very easy to
combine un-namespaced code that uses namespaces, and namespaced code.
Also very important to note is that the "namespace {}" syntax is
optional for any code that does not import other things via the "use"
statement - its sole purpose is to provide a clear visual and logical
wrapper within which imports occur.
Thus, this is also legal:
<?php
namespace newly\coded\stuff {
class mine { ... }
}
// old stuff here
class PEAR { ... }
?>>
Lastly, if global code does make use of namespaces, but does not import
anything, it can also happily co-exist with bracketed namespace code:
<?php
namespace ns {
class mine { ... }
}
$a = new ns\mine;
// and so on
?>>
Thanks,
Greg
Best regards,
Marcus