[PATCH] bracketed namespace, unset import, removal of namespace blah;

php.internals

Greg Beaver

19 years ago
Hi again, The attached patch: 1) adds "unset import" syntax for declaring a namespace to have local import scope (it does NOT affect variable scope or the global class/function table) 2) removes "namespace Name;" syntax (this I am happy to add this back in if there is uproar) 3) fixes all misspellings of "coflict" in zend_compile.c (2 total) 4) uses a more intuitive error message "Namespace 'Foo' cannot be nested (already within 'Bar' namespace)" for nested namespaces 5) updates tests to use brackets it can also be found at http://pear.php.net/~greg/namespace_brackets_unsetimport.patch.txt After Stanislav's criticisms of my "smart import" namespace patch and David's criticism of confusing dual syntax, I decided to take another approach to the import issue. Although I would rather only support one use case of namespace blah {}, I do think that realistically PHP should be as intuitive as possible. Having a separate scope by default for import that does not inherit from the global scope is not very intuitive. So, instead of resetting current_import by default, this patch makes import global by default and local by explicit syntax via: namespace MyNamespace unset import { } For example: <?php import foo::bar; namespace foo { class bar { function __construct() { echo __NAMESPACE__ . "::bar\n"; } } // foo::bar new bar; } namespace gronk unset import { import foo::bar as foobar; // uses local import class bar extends foobar { function __construct() { echo __NAMESPACE__ . "::bar\n"; } } // gronk::bar new bar; // foo::bar new foobar; } namespace last { // uses global import // foo::bar new bar; } // uses global import // foo::bar new bar; ?> This code demonstrates that in the (useless) namespace last {} declaration, we can access the global import. This way, since import conflicts are not the norm but the exception, they can be handled on a case-by-case basis. Let's remember that in most cases users will not be declaring multiple namespaces, but instead doing this use case for the import keyword: <?php require 'library1/foo.php'; require 'framework2/foo.php'; import framework2::foo as foo; import library1::foo as bar; ... ?> Again, the primary use case for multiple namespaces in the same file that I hope to support is combining multiple pre-existing files into a single file. As each file is expected to be self-contained, this means that by having import statements within the namespace {} declaration and using unset import the files are guaranteed to combine with any other separate file that follows these rules. Even if authors do not use unset import, it can easily be added by hand or automatically when glomming the separate files into a single file. Files with global imports will be out of luck if there are naming conflicts with the global namespace (similar to today's pre-namespace conundrum), but as class files or functions are almost always libraries of some kind, this is unlikely if the documentation is clear on best practices. Greg

M. Sokolewicz

19 years ago
Gregory Beaver wrote:
> Hi again, > > The attached patch: > 1) adds "unset import" syntax for declaring a namespace to have local > import scope (it does NOT affect variable scope or the global > class/function table) > 2) removes "namespace Name;" syntax (this I am happy to add this back in > if there is uproar) > 3) fixes all misspellings of "coflict" in zend_compile.c (2 total) > 4) uses a more intuitive error message "Namespace 'Foo' cannot be nested > (already within 'Bar' namespace)" for nested namespaces > 5) updates tests to use brackets > > it can also be found at > http://pear.php.net/~greg/namespace_brackets_unsetimport.patch.txt > > After Stanislav's criticisms of my "smart import" namespace patch and > David's criticism of confusing dual syntax, I decided to take another > approach to the import issue. Although I would rather only support one > use case of namespace blah {}, I do think that realistically PHP should > be as intuitive as possible. Having a separate scope by default for > import that does not inherit from the global scope is not very intuitive. > > So, instead of resetting current_import by default, this patch makes > import global by default and local by explicit syntax via: > > namespace MyNamespace unset import { > } > > > For example: > <?php > import foo::bar; > > namespace foo { > class bar { > function __construct() > { > echo __NAMESPACE__ . "::bar\n"; > } > } > // foo::bar > new bar; > } > > > namespace gronk unset import { > import foo::bar as foobar; > // uses local import > class bar extends foobar { > function __construct() > { > echo __NAMESPACE__ . "::bar\n"; > } > } > // gronk::bar > new bar; > // foo::bar > new foobar; > } > > namespace last { > // uses global import > // foo::bar > new bar; > } > // uses global import > // foo::bar > new bar; > ?> > > This code demonstrates that in the (useless) namespace last {} > declaration, we can access the global import. This way, since import > conflicts are not the norm but the exception, they can be handled on a > case-by-case basis. Let's remember that in most cases users will not be > declaring multiple namespaces, but instead doing this use case for the > import keyword: > > <?php > require 'library1/foo.php'; > require 'framework2/foo.php'; > > import framework2::foo as foo; > import library1::foo as bar; > ... > ?> > > Again, the primary use case for multiple namespaces in the same file > that I hope to support is combining multiple pre-existing files into a > single file. As each file is expected to be self-contained, this means > that by having import statements within the namespace {} declaration and > using unset import the files are guaranteed to combine with any other > separate file that follows these rules. Even if authors do not use > unset import, it can easily be added by hand or automatically when > glomming the separate files into a single file. > > Files with global imports will be out of luck if there are naming > conflicts with the global namespace (similar to today's pre-namespace > conundrum), but as class files or functions are almost always libraries > of some kind, this is unlikely if the documentation is clear on best > practices. > > Greg >
I'm not sure if this is the best way to take it, to be honest I had to re-read your post 2x to figure out what was actually going on and why. The unset import part is odd and not very transparent to the average user (imo). Sure, with good documentation you could solve that, but imo we should look for easier to understand syntax instead. I like the idea, but it adds a lot of complexity with (as far as I can tell) little gain vs. the original 1-file-1-namespace patch.

Derick Rethans

19 years ago
On Wed, 22 Aug 2007, M. Sokolewicz wrote:
> I'm not sure if this is the best way to take it, to be honest I had to > re-read your post 2x to figure out what was actually going on and why. > The unset import part is odd and not very transparent to the average > user (imo). Sure, with good documentation you could solve that, but > imo we should look for easier to understand syntax instead. I like the > idea, but it adds a lot of complexity with (as far as I can tell) > little gain vs. the original 1-file-1-namespace patch.
I have exactly the same feeling... is it really necesary to make this complex again? I don't care much about the namespace definition syntax, but the concept that was just posted here has IMO a big WTF factor. KISS people... Derick

Stanislav Malyshev

19 years ago
> 1) adds "unset import" syntax for declaring a namespace to have local > import scope (it does NOT affect variable scope or the global > class/function table)
I don't like it. What's "unset import"? Seems to be very artificial concept.
> be as intuitive as possible. Having a separate scope by default for > import that does not inherit from the global scope is not very intuitive.
Yep, it isn't. But it's the only concept that we saw so far that is consistent and logical.
> So, instead of resetting current_import by default, this patch makes > import global by default and local by explicit syntax via:
But this syntax, unfortunately, doesn't make it better. If the user would have to manually control all the imports it'd be very irritating. And what if he wants to keep one import and not keep another? Also, the problem of namespace being influenced by external code still not solved.
-- Stanislav Malyshev, Zend Software Architect stas@zend.com http://www.zend.com/ (408)253-8829 MSN: stas@zend.com

Greg Beaver

19 years ago
Stanislav Malyshev wrote:
>> 1) adds "unset import" syntax for declaring a namespace to have local >> import scope (it does NOT affect variable scope or the global >> class/function table) > > I don't like it. What's "unset import"? Seems to be very artificial > concept. > >> be as intuitive as possible. Having a separate scope by default for >> import that does not inherit from the global scope is not very >> intuitive. > > Yep, it isn't. But it's the only concept that we saw so far that is > consistent and logical.
Hi, The purpose of all my patches is to make it possible to combine multiple namespaces into a single file. It looks like namespace {} syntax introduces much more trouble than it is worth. As such, since my only goal is to be able to combine multiple files into a single file, the attached patch basically allows you to take these two files: file1.php: <?php namespace one; class whatever { } other_php_stuff(); ?> file2.php: <?php include 'file1.php'; namespace two; function thingo() {} ?> and literally cut/paste them together to get: <?php namespace one; class whatever { } other_php_stuff(); namespace two; function thingo() {} ?> The patch acts as if each namespace were a separate file with respect to import statements as well as class/function declarations. The only limitation is that a situation like so: file1.php <?php include 'file2.php'; function thing() {} one::thing(); ?> file2.php: <?php namespace one; function thing() {echo 'hi';} ?> combine erroneously into the "one" namespace <?php namespace one; function thing() {echo 'hi';} function thing() {} one::thing(); ?> The solution, which is a simple one, is upon combining to insert a bogus namespace declaration for the contents of file1.php, and is a simple one for a build tool or a developer to accomplish. Developers who would combine files together would need to scan for include statements if autoload was not used, and scanning for missing namespace declarations is trivial in this situation: <?php namespace one; function thing() {echo 'hi';} namespace __::__main; function thing() {} one::thing(); ?> Can we agree on this patch? It preserves the original simple syntax that I like so much (no brackets), solves the import scoping problem, and allows combining files without removing the structure in namespacing. It also discourages using multiple namespaces per file, as the ease of using import across namespace declarations is gone. Finally, it preserves the need of the first namespace declaration being at the top of the file, another appealing feature of the original syntax. The attached patch is also at http://pear.php.net/~greg/multiple_namespaces.patch.txt Thanks for your patience, Greg

Stanislav Malyshev

19 years ago
> The purpose of all my patches is to make it possible to combine multiple > namespaces into a single file. It looks like namespace {} syntax > introduces much more trouble than it is worth.
Heh, why do you think we chose not to do it - because we are bracketophobic bigots? ;)
> file2.php: > <?php > include 'file1.php'; > namespace two; > function thingo() {} > ?>
Not sure what this one does, esp. include but if it's just global space there than ok.
> <?php > namespace one; > class whatever { > } > other_php_stuff(); > > namespace two; > function thingo() {} > ?>
I think we could live with this one, import problems are less severe then. We still need to check if we don't have any weird cases, but if we don't find any then it might work...
> <?php > namespace one; > function thing() {echo 'hi';} > > namespace __::__main; > function thing() {} > one::thing(); > ?>
__::__ look like some weird ASCII art, maybe we need something better for it.
-- Stanislav Malyshev, Zend Software Architect stas@zend.com http://www.zend.com/ (408)253-8829 MSN: stas@zend.com

Greg Beaver

19 years ago
Stanislav Malyshev wrote:
>> >> namespace __::__main; >> function thing() {} >> one::thing(); >> ?> > > __::__ look like some weird ASCII art, maybe we need something better > for it.
:) it could be anything, really, I just figured there's no chance that would conflict with any other namespace. I suppose in this situation we could allow resetting to global with "namespace;" or "namespace ::;" but honestly, I don't see a compelling reason to do that when it's such an edge case. Greg

Cristian Rodriguez

19 years ago
On 8/21/07, Gregory Beaver <greg@chiaraquartet.net> wrote:
> Hi again, > > The attached patch: > 1) adds "unset import" syntax for declaring a namespace to have local > import scope (it does NOT affect variable scope or the global > class/function table)
huh ? o_O unset import ? that's really weird.