# [PATCH] bracketed namespace declarations

- Thread: https://externals.io/message/41766
- Original archive: https://news-web.php.net/php.internals/41766
- Started by Gregory Beaver on 2008-11-07T21:14:50+00:00
- Messages: 9
- 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

---

## #41766 — Gregory Beaver — 2008-11-07T21:14:50+00:00

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

Hi,

Stas and company decided that they wanted namespaces to have two legal
syntax choices:

1) single namespace per file:

<?php
namespace foo;
...
?>

2) 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

---

## #41767 — Stan Vassilev | FM — 2008-11-07T21:36:31+00:00

URL: https://externals.io/message/41766#41767 · In reply to: #41766

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

---

## #41768 — Stan Vassilev | FM — 2008-11-07T21:49:36+00:00

URL: https://externals.io/message/41766#41768 · In reply to: #41766

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

---

## #41769 — Gregory Beaver — 2008-11-07T21:53:54+00:00

URL: https://externals.io/message/41766#41769 · In reply to: #41767

Stan Vassilev | FM wrote:

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

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

---

## #41770 — Kenan R Sulayman — 2008-11-07T22:06:36+00:00

URL: https://externals.io/message/41766#41770 · In reply to: #41768

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

---

## #41771 — Stan Vassilev | FM — 2008-11-07T22:20:02+00:00

URL: https://externals.io/message/41766#41771 · In reply to: #41769

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

---

## #41773 — Steph Fox — 2008-11-08T14:06:56+00:00

URL: https://externals.io/message/41766#41773 · In reply to: #41769

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

---

## #41774 — Gregory Beaver — 2008-11-08T15:07:24+00:00

URL: https://externals.io/message/41766#41774 · In reply to: #41773

Steph Fox wrote:
> Hey Greg,
> 
> > […]
> 
> 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

---

## #41800 — Marcus Boerger — 2008-11-10T10:49:58+00:00

URL: https://externals.io/message/41766#41800 · In reply to: #41766

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:

> 1) single namespace per file:

> <?php
> namespace foo;
> ...
?>>

> 2) 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
