Re: AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
I thought global names were considered in the patch, but now that I re-read Dmitry's post, only symbols in the namespace and internal symbols are considered. I read through most of the posts regarding namespaces, but could not find a reason why global names are not looked up. Classes/functions should first be looked up in the current namespace, if not found, then they should be looked up in the global namespace, and if it is not found there either, then there should be a check to see if there is an internal class/function with the same name. Dmitry, what's the reason this lookup logic wasn't used in your patch? Regards, Jessie Gregory Beaver wrote: Jessie Hernandez wrote: Hi Greg, How about this: any non-namespaced file that uses use statements is implicitly put into the __php__ namespace (or whatever other name is chosen, or having the namespace name be the path of the file)? With this, use will never import any symbols into the global namespace. Hi Jessie, Imagine how that would affect this code: file1.php: ?php function doSomething() {} ? PEAR2/DB.php: hypothetical ?php namespace PEAR2; class DB {} ? file2.php: ?php include 'file1.php'; include 'PEAR2/DB.php'; use PEAR2::DB; $a = new DB; $b = doSomething(); ? In file2.php, because there is a use statement, the rest of the file is assumed to be in the __php__ namespace. As such, the file can be expanded into this code: new_file2.php: ?php namespace __php__; include 'file1.php'; include 'file2.php'; $a = new PEAR2::DB; $b = doSomething(); ? On the last line, when PHP calls doSomething(), it first checks to see if the function doSomething is available as an internal function. Then, it tries __php__::doSomething() and fails on a fatal error because the function does not exist. The only way that your idea would work is if the check for doSomething consisted of checking for any non-namespaced function (not just internal functions), but the sole purpose of the fall-through is to allow users to call internal functions/classes without explicitly specifying ::strlen or ::count and so on. Allowing fall-through to any global class/function would serve to dilute the namespacing effect, but perhaps this is a good thing? I have not thought about this long enough to have a definitive opinion yet. I think one safe way to handle this might be to have an E_STRICT if class/function/const is declared in the __php__ namespace, so that PHP provides a clear mechanism for enforcing the convention. Users wishing to avoid this E_STRICT need only use another namespace name or adhere to the coding convention of only putting stuff that uses code into the __php__ namespace. Greg -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
I agree with this 100%, is this something that could be changed? I don't see a reason behind it. On Sun, 2007-12-09 at 16:24 -0500, Jessie Hernandez wrote: internal class/function with the same name. Dmitry, what's the reason this lookup logic wasn't used in your patch? -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Jessie Hernandez wrote: I thought global names were considered in the patch, but now that I re-read Dmitry's post, only symbols in the namespace and internal symbols are considered. I read through most of the posts regarding namespaces, but could not find a reason why global names are not looked up. Classes/functions should first be looked up in the current namespace, right. if not found, then they should be looked up in the global namespace, never. I have no idea why do you think they should look there... and if it is not found there either, then there should be a check to see if there is an internal class/function with the same name. Today all internal classes/functions are in the global namespace. We allowed usage of internal names in namespaces, because it would be terrible to prefix each usage of internal function like strlen(), write(). Dmitry. Dmitry, what's the reason this lookup logic wasn't used in your patch? Regards, Jessie Gregory Beaver wrote: Jessie Hernandez wrote: Hi Greg, How about this: any non-namespaced file that uses use statements is implicitly put into the __php__ namespace (or whatever other name is chosen, or having the namespace name be the path of the file)? With this, use will never import any symbols into the global namespace. Hi Jessie, Imagine how that would affect this code: file1.php: ?php function doSomething() {} ? PEAR2/DB.php: hypothetical ?php namespace PEAR2; class DB {} ? file2.php: ?php include 'file1.php'; include 'PEAR2/DB.php'; use PEAR2::DB; $a = new DB; $b = doSomething(); ? In file2.php, because there is a use statement, the rest of the file is assumed to be in the __php__ namespace. As such, the file can be expanded into this code: new_file2.php: ?php namespace __php__; include 'file1.php'; include 'file2.php'; $a = new PEAR2::DB; $b = doSomething(); ? On the last line, when PHP calls doSomething(), it first checks to see if the function doSomething is available as an internal function. Then, it tries __php__::doSomething() and fails on a fatal error because the function does not exist. The only way that your idea would work is if the check for doSomething consisted of checking for any non-namespaced function (not just internal functions), but the sole purpose of the fall-through is to allow users to call internal functions/classes without explicitly specifying ::strlen or ::count and so on. Allowing fall-through to any global class/function would serve to dilute the namespacing effect, but perhaps this is a good thing? I have not thought about this long enough to have a definitive opinion yet. I think one safe way to handle this might be to have an E_STRICT if class/function/const is declared in the __php__ namespace, so that PHP provides a clear mechanism for enforcing the convention. Users wishing to avoid this E_STRICT need only use another namespace name or adhere to the coding convention of only putting stuff that uses code into the __php__ namespace. Greg -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Hi Matthias, Let alone __php__. If you just put all of your code into namespace Mylib, you're not safe because according to the name resolution rules, internal classes come after imported ones but before trying to find classes in the current namespace. I'd missed that :-( and from what I gather, there's no way to safely change it either. OK, apologies for the noise. - Steph -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Matthias Pigulla wrote: Von: Gregory Beaver [mailto:[EMAIL PROTECTED] Exactly - which is why you should never put classes, functions or constants in the __php__ namespace. The convention I am proposing is to only use __php__ for code that *uses* re-usable components, not *declares* them. Let alone __php__. If you just put all of your code into namespace Mylib, you're not safe because according to the name resolution rules, internal classes come after imported ones but before trying to find classes in the current namespace. Right, but as long as you know this, it is not so bad for two reasons, see below. Even if you *don't* know this, the chance of a name collision is extremely unlikely - the most common collision will be Exception. 1) library code is always explicitly used 2) name conflicts are impossible 1) is the crucial one because that puts your classes ahead of the internal ones in the resolution list. That is not only library code you explicitly use, but also all code from your own namespace. Having to explicitly enumerate all classes you use in your own namespace in every file may be tedious. So just to get that straight: Having a namespace statement and no use (because all you use is from your library) is a discouraged practise? To be clear - this *only* affects users who are relying on autoload. In other words, this code works the same way 100% of the time regardless of load order: file1.php: ?php namespace foo; class Exception {} ? file2.php: ?php namespace foo; include 'file1.php'; $a = new Exception('hi'); echo get_class($a); // foo::Exception ? So, if your code explicitly loads external files using include/require, you need not worry about this issue. Library authors who are in fact relying upon autoload do need to explicitly use the classes they import as unqualified names, but this is far less onerous than it seems on initial thought. Let's say you're using 10 classes from your own project. The first instinct is that you then have to have 10 use lines - what a pain! However, this is not necessary. Here's a realistic sample from PEAR2_Pyrus's package.xml validator class, PEAR2::Pyrus::PackageFile::v2::Validator. ?php namespace PEAR2::Pyrus::PackageFile::v2; use PEAR2::Pyrus::PackageFile as pf; use PEAR2::Pyrus::PackageFile::Exception as _ex use PEAR2::Pyrus as me; class Validator {...} // details removed for brevity :) ? With the above use statements, I can access these classes: PEAR2::Pyrus::PackageFile::v2 PEAR2::Pyrus::Validate PEAR2::Pyrus::PackageFile::Exception PEAR2::Pyrus::ChannelRegistry PEAR2::Pyrus::Installer::Role PEAR2::Pyrus::Config PEAR2::Pyrus::Config::Exception PEAR2::Pyrus::Task PEAR2::Pyrus::Log PEAR2::Pyrus::Package::Tar with these shortcuts: pf::v2 me::Validate _ex me::ChannelRegistry me::Installer::Role me::Config me::Config::Exception me::Task me::Log me::Package::Tar Note that it would be possible to shorten the longer names like me::Config::Exception, but these classnames are only used once in the file. The most commonly used classname is PEAR2::Pyrus::PackageFile::Exception, and so I would choose that as the shortest name. When one examines these things from a practical standpoint, having the 4 extra characters me:: definitely increases maintainability, as it makes it obvious that this class is from our library, and not an internal class. I do think it would be worth putting future internal classes into the PHP namespace, and it would be a good idea to reserve that namespace now. The reservation can always be dropped later if necessary. Greg -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Hi Greg, How about this: any non-namespaced file that uses use statements is implicitly put into the __php__ namespace (or whatever other name is chosen, or having the namespace name be the path of the file)? With this, use will never import any symbols into the global namespace. Regards, Jessie Ford, Mike wrote: On 07 December 2007 17:36, Gregory Beaver wrote: The suggestion to make namespace __php__; implicit is very interesting, but would defeat its purpose, which is to separate declarations from use. Oh, I missed that little wrinkle -- I did say I was only skimming! I guess it could still be done, but at somewhat greater cost in the engine than I was imagining, which probably isn't worthwhile. Cheers! Mike - Mike Ford, Electronic Information Services Adviser, JG125, The Headingley Library, James Graham Building, Leeds Metropolitan University, Headingley Campus, LEEDS, LS6 3QS, United Kingdom Email: [EMAIL PROTECTED] Tel: +44 113 812 4730 Fax: +44 113 812 3211 To view the terms under which this email is distributed, please go to http://disclaimer.leedsmet.ac.uk/email.htm -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Jessie Hernandez wrote: Hi Greg, How about this: any non-namespaced file that uses use statements is implicitly put into the __php__ namespace (or whatever other name is chosen, or having the namespace name be the path of the file)? With this, use will never import any symbols into the global namespace. Hi Jessie, Imagine how that would affect this code: file1.php: ?php function doSomething() {} ? PEAR2/DB.php: hypothetical ?php namespace PEAR2; class DB {} ? file2.php: ?php include 'file1.php'; include 'PEAR2/DB.php'; use PEAR2::DB; $a = new DB; $b = doSomething(); ? In file2.php, because there is a use statement, the rest of the file is assumed to be in the __php__ namespace. As such, the file can be expanded into this code: new_file2.php: ?php namespace __php__; include 'file1.php'; include 'file2.php'; $a = new PEAR2::DB; $b = doSomething(); ? On the last line, when PHP calls doSomething(), it first checks to see if the function doSomething is available as an internal function. Then, it tries __php__::doSomething() and fails on a fatal error because the function does not exist. The only way that your idea would work is if the check for doSomething consisted of checking for any non-namespaced function (not just internal functions), but the sole purpose of the fall-through is to allow users to call internal functions/classes without explicitly specifying ::strlen or ::count and so on. Allowing fall-through to any global class/function would serve to dilute the namespacing effect, but perhaps this is a good thing? I have not thought about this long enough to have a definitive opinion yet. I think one safe way to handle this might be to have an E_STRICT if class/function/const is declared in the __php__ namespace, so that PHP provides a clear mechanism for enforcing the convention. Users wishing to avoid this E_STRICT need only use another namespace name or adhere to the coding convention of only putting stuff that uses code into the __php__ namespace. Greg -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
I agree with everything here, especially the solution to multiple namespaces per file (allow but discourage), but i don't agree with the __php__ namespace. If any separation of core php and extensions into namespaces happens, it should be kept as simple as possible, with root namespaces like php:: and ext::. The application should be allowed to define its own root namespace, or use a namespace such as app::. Besides that I think all of your other suggestions are the best ones. On Thu, 2007-12-06 at 19:36 -0600, Gregory Beaver wrote: Hi Derick, I've been thinking a *lot* about your provocative email in the past couple of days, and have come to a different conclusion from my original reply (which, as a reminder stated I saw no problem with removing namespaces as long as we kept the import facility to alias classes via use). After a few hours of thinking practically about the implementation, I realized that this would be impossible for the same reasons as your first argument. So, I set out to find a solution that keeps namespaces and solves the problems. I have found the solutions to every problem I could find, and to my surprise, even after crafting a new patch to solve some of them, have found a way to solve all of the problems within the existing implementation (with a few tweaks, but nothing major changed) or by specifying new coding conventions. Summary: 1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. 2) use Name::*; is technically impossible without some kind of autoloading mechanism, but can be reasonably approximated by importing a long namespace name as a shorter one. use PEAR2::Really::Long::Name as a; then allows referring to PEAR2::Really::Long::Name::Classname as a::Classname, and PEAR2::Really::Long::Subnamespace::Classname as a::Subnamespace::Classname. 3) multiple namespaces per file should be allowed, but strongly discouraged as a coding practice of last resort for most users. 4) brackets for namespaces is most necessary for hierarchical namespace implementations. This is not such an implementation, and as such brackets do not add clarity but do slow down the implementation. 5) namespaces provide these benefits that are not available in PHP: a) short, unqualified descriptive class names can be used without fear of conflicting with an internal class b) a clear, uniform coding convention on how to avoid conflicts between your code and others that will help those who have to maintain the code of others. c) a way to alias longer names to increase readability and maintainability of code. 6) There are some dangers when using namespaces with autoload, but simple ways of thwarting those dangers. Also dangerous is trusting external code that is in the same namespace, as functions can be redefined. Detailed answers: Derick Rethans wrote: 1. As it is impossible to do use XXX as NativeClass we get to the snip extension (DateTime, DateTimeZone). However introducing the new class DateTimeSpan might break people's code that do things like: ?php use myNamespace::DateTimeZone as DateTimeZone; ? This is indeed the biggest problem. However, it only exists in the global namespace (non-namespaced code). An example script using the non-existing hypothetical PEAR2::DateTime class: ?php include 'PEAR2/Autoload.php'; use PEAR2::DateTime; // fatal error - use name conflicts with internal class $a = new DateTime; ? However, the answer is simple and elegant. PHP applications that take advantage of namespaces should use a namespace *in the application global code* that is reserved for application code, like __php__. ?php namespace __php__; include 'PEAR2/Autoload.php'; use PEAR2::DateTime; $a = new DateTime; // $a is an object of class PEAR2::DateTime after autoloading, or if a previously included file has declared class DateTime in namespace PEAR ? Note that the only difference here is the addition of 1 line of code at the top of the file. On the same token, this code: ?php namespace __php__; $a = new DateTime; // $a is an object of class ::DateTime ? works as expected, accessing the internal DateTime class directly. In other words, 1 line of code is needed to take advantage of namespace's full protection and ability to import conflicting class names into the global (in this case unqualified, not containing :: in the name) scope, while at the same time preserving BC with existing code (no modification needed beyond addition of namespace __php__;). I recommend that the manual specify this convention, and will happily take on the documentation of it. 2. You have to import every class yourself. You can currently not do: use myNamespace::* as *; // or similar
Re: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
On Thu, 6 Dec 2007, Gregory Beaver wrote: I've been thinking a *lot* about your provocative email in the past couple of days, and have come to a different conclusion from my original reply (which, as a reminder stated I saw no problem with removing namespaces as long as we kept the import facility to alias classes via use). After a few hours of thinking practically about the implementation, I realized that this would be impossible for the same reasons as your first argument. So, I set out to find a solution that keeps namespaces and solves the problems. Right, that was the idea behind the mail :) As yours is pretty long, I'm only going to respond to the main points. 1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. 2) use Name::*; is technically impossible without some kind of autoloading mechanism, but can be reasonably approximated by importing a long namespace name as a shorter one. use PEAR2::Really::Long::Name as a; then allows referring to PEAR2::Really::Long::Name::Classname as a::Classname, and PEAR2::Really::Long::Subnamespace::Classname as a::Subnamespace::Classname. Yeah, I know... I don't really care about this myself anyway - it's just something that I heard in discussions. [snip] Detailed answers: Derick Rethans wrote: 1. As it is impossible to do use XXX as NativeClass we get to the snip extension (DateTime, DateTimeZone). However introducing the new class DateTimeSpan might break people's code that do things like: ?php use myNamespace::DateTimeZone as DateTimeZone; ? This is indeed the biggest problem. However, it only exists in the global namespace (non-namespaced code). An example script using the non-existing hypothetical PEAR2::DateTime class: ?php include 'PEAR2/Autoload.php'; use PEAR2::DateTime; // fatal error - use name conflicts with internal class $a = new DateTime; ? However, the answer is simple and elegant. PHP applications that take advantage of namespaces should use a namespace *in the application global code* that is reserved for application code, like __php__. ?php namespace __php__; include 'PEAR2/Autoload.php'; use PEAR2::DateTime; $a = new DateTime; // $a is an object of class PEAR2::DateTime after autoloading, or if a previously included file has declared class DateTime in namespace PEAR ? Note that the only difference here is the addition of 1 line of code at the top of the file. On the same token, this code: ?php namespace __php__; $a = new DateTime; // $a is an object of class ::DateTime ? works as expected, accessing the internal DateTime class directly. In other words, 1 line of code is needed to take advantage of namespace's full protection and ability to import conflicting class names into the global (in this case unqualified, not containing :: in the name) scope, while at the same time preserving BC with existing code (no modification needed beyond addition of namespace __php__;). I recommend that the manual specify this convention, and will happily take on the documentation of it. 2. You have to import every class yourself. You can currently not do: use myNamespace::* as *; // or similar syntax [snip] There are ways of simulating use myNamespace::* as *; that are almost as complete and are actually better for long-term maintenance. For instance, let's say you want to use several classes from PEAR2::Ultra::Long::Package::Name. You don't need to use each class individually, you can import the entire namespace: ?php namespace __php__; use PEAR2::Ultra::Long::Package::Name; $a = new Name::ExampleClass; $b = new Name::SecondThing; $c = new Name::ThirdThing; ? Sounds like a good idea. I have no strong opinion on {}, but I do see a compelling argument in favor of not using {} for performance reasons if you're only going to use 1 namespace per file except in extraordinary circumstances. The only thing that in the case you *have* a multi-namespace file, using braces would editors allow to the start and end of a namespace easily (f.e. VIM's %). A larger danger is this example: ?php namespace foo; echo strlen('hi'); include 'maliciousfile.php'; echo strlen('hi'); ? maliciousfile.php: ?php namespace foo; function strlen($a) { // do bad stuff echo I'm evil return ::strlen($a); } ? The above script outputs 2I'm evil2 - foo::strlen() is called for the second call to strlen(). I thought only constants and classes could be parts of namespaces? regards, Derick -- Derick Rethans http://derickrethans.nl | http://ezcomponents.org | http://xdebug.org -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
RE: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
On 07 December 2007 01:36, Gregory Beaver wrote: [...snip...] In other words, 1 line of code is needed to take advantage of namespace's full protection and ability to import conflicting class names into the global (in this case unqualified, not containing :: in the name) scope, while at the same time preserving BC with existing code (no modification needed beyond addition of namespace __php__;). I recommend that the manual specify this convention, and will happily take on the documentation of it. I've only been skimming the namespace argument, so forgive me if this is totally non-sensible, but if such usage is fully BC, and has only upsides with no downside, would there be any mileage in making it implicit rather than explicit -- i.e., any code not explicitly namespaced is automatically in the reserved namespace __php__? Such usage could be completely invisible to your everyday PHP user, and only need explaining in an intro to namespaces section. Cheers! Mike Mike Ford, Electronic Information Services Adviser, JG125, The Headingley Library James Graham Building, Headingley Campus Tel: extn 24730Fax: extn 23211 To view the terms under which this email is distributed, please go to http://disclaimer.leedsmet.ac.uk/email.htm
Re: AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Matthias Pigulla wrote: 1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. 5) namespaces provide these benefits that are not available in PHP: a) short, unqualified descriptive class names can be used without fear of conflicting with an internal class Interesting as I was not aware before that when a namespace is active the import goes into that namespace and not into global scope (clashing with core classes there). But please consider: -- Date.php -- ?php namespace __php__; class Date {} ? -- test.php -- ?php namespace __php__; require_once('autoload.php'); // assume it would require Date.php when asked to do so print get_class(new Date()); ? Although this code has been future-proofed by adding the namespace __php__, it will break if the core introduces a class named Date (will use the wrong class!). It also breaks without the namespace, and maybe it is a mistake to rely on autload here. But this is a case where using namespaces does not protect you from surprises unless you explicitly import (use) all the classes you need. But that is not as simple as putting a namespace statement on top of all your files to be save. If new, future core extensions showed up in a reserved PHP:: namespace, you would be :-). Exactly - which is why you should never put classes, functions or constants in the __php__ namespace. The convention I am proposing is to only use __php__ for code that *uses* re-usable components, not *declares* them. In this case, your example would be revised as: ?php namespace Mylib; class Date {} ? ?php namespace __php__; use Mylib::Date; include 'autoload.php'; // note - require_once and () just slow things down $a = new Date(); ? This convention serves two purposes 1) library code is always explicitly used 2) name conflicts are impossible The suggestion to make namespace __php__; implicit is very interesting, but would defeat its purpose, which is to separate declarations from use. Another off-list suggestion was to make use outside of a namespace declaration an error, as this is generally a bad idea that can lead to many gotchas. Greg -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Hi Greg, 1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. That answers my main concern, but I'd make it stronger than a recommendation. I'd make it impossible to import namespaced code into the global space. - Steph -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. 5) namespaces provide these benefits that are not available in PHP: a) short, unqualified descriptive class names can be used without fear of conflicting with an internal class Interesting as I was not aware before that when a namespace is active the import goes into that namespace and not into global scope (clashing with core classes there). But please consider: -- Date.php -- ?php namespace __php__; class Date {} ? -- test.php -- ?php namespace __php__; require_once('autoload.php'); // assume it would require Date.php when asked to do so print get_class(new Date()); ? Although this code has been future-proofed by adding the namespace __php__, it will break if the core introduces a class named Date (will use the wrong class!). It also breaks without the namespace, and maybe it is a mistake to rely on autload here. But this is a case where using namespaces does not protect you from surprises unless you explicitly import (use) all the classes you need. But that is not as simple as putting a namespace statement on top of all your files to be save. If new, future core extensions showed up in a reserved PHP:: namespace, you would be :-). -mp.
Re: AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
On Friday 07 December 2007, Gregory Beaver wrote: If new, future core extensions showed up in a reserved PHP:: namespace, you would be :-). Exactly - which is why you should never put classes, functions or constants in the __php__ namespace. The convention I am proposing is to only use __php__ for code that *uses* re-usable components, not *declares* them. In this case, your example would be revised as: ?php namespace Mylib; class Date {} ? ?php namespace __php__; use Mylib::Date; include 'autoload.php'; // note - require_once and () just slow things down $a = new Date(); ? This convention serves two purposes 1) library code is always explicitly used 2) name conflicts are impossible The suggestion to make namespace __php__; implicit is very interesting, but would defeat its purpose, which is to separate declarations from use. Another off-list suggestion was to make use outside of a namespace declaration an error, as this is generally a bad idea that can lead to many gotchas. Greg Doesn't strict C++ also have a requirement for a global namespace definition? It has been a very long time since I did any C++, but I seem to recall a requirement for a use std or something like that directive that I never actually understood. :-) If there is a named global namespace __php__, then requiring it in order to import anything makes sense. It's one extra line of code and doesn't break BC anymore than using the use keyword does. Another observation, if one takes the position that library code and running code should always be separated, this setup would encourage that best practice but does not absolutely require it. That fits with the doing something dumb should be hard, but not impossible philosophy. :-) That recommendation would definitely need to be well-documented. I overall like this concept. Kudos to Greg, as others have said. One question I would have is what is the performance hit of braces over a keyword? (Not a challenge; I genuinely don't know what the C implementation differences would be that would make a difference.) -- Larry Garfield AIM: LOLG42 [EMAIL PROTECTED] ICQ: 6817012 If nature has made any one thing less susceptible than all others of exclusive property, it is the action of the thinking power called an idea, which an individual may exclusively possess as long as he keeps it to himself; but the moment it is divulged, it forces itself into the possession of every one, and the receiver cannot dispossess himself of it. -- Thomas Jefferson -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
AW: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Von: Gregory Beaver [mailto:[EMAIL PROTECTED] Exactly - which is why you should never put classes, functions or constants in the __php__ namespace. The convention I am proposing is to only use __php__ for code that *uses* re-usable components, not *declares* them. Let alone __php__. If you just put all of your code into namespace Mylib, you're not safe because according to the name resolution rules, internal classes come after imported ones but before trying to find classes in the current namespace. 1) library code is always explicitly used 2) name conflicts are impossible 1) is the crucial one because that puts your classes ahead of the internal ones in the resolution list. That is not only library code you explicitly use, but also all code from your own namespace. Having to explicitly enumerate all classes you use in your own namespace in every file may be tedious. So just to get that straight: Having a namespace statement and no use (because all you use is from your library) is a discouraged practise? Thanks! -mp.
Re: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Great work! +1 from me for your proposals, too! Roman On Dec 7, 2007, at 2:36 AM, Gregory Beaver wrote: Hi Derick, I've been thinking a *lot* about your provocative email in the past couple of days, and have come to a different conclusion from my original reply (which, as a reminder stated I saw no problem with removing namespaces as long as we kept the import facility to alias classes via use). After a few hours of thinking practically about the implementation, I realized that this would be impossible for the same reasons as your first argument. So, I set out to find a solution that keeps namespaces and solves the problems. I have found the solutions to every problem I could find, and to my surprise, even after crafting a new patch to solve some of them, have found a way to solve all of the problems within the existing implementation (with a few tweaks, but nothing major changed) or by specifying new coding conventions. Summary: 1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. 2) use Name::*; is technically impossible without some kind of autoloading mechanism, but can be reasonably approximated by importing a long namespace name as a shorter one. use PEAR2::Really::Long::Name as a; then allows referring to PEAR2::Really::Long::Name::Classname as a::Classname, and PEAR2::Really::Long::Subnamespace::Classname as a::Subnamespace::Classname. 3) multiple namespaces per file should be allowed, but strongly discouraged as a coding practice of last resort for most users. 4) brackets for namespaces is most necessary for hierarchical namespace implementations. This is not such an implementation, and as such brackets do not add clarity but do slow down the implementation. 5) namespaces provide these benefits that are not available in PHP: a) short, unqualified descriptive class names can be used without fear of conflicting with an internal class b) a clear, uniform coding convention on how to avoid conflicts between your code and others that will help those who have to maintain the code of others. c) a way to alias longer names to increase readability and maintainability of code. 6) There are some dangers when using namespaces with autoload, but simple ways of thwarting those dangers. Also dangerous is trusting external code that is in the same namespace, as functions can be redefined. Detailed answers: Derick Rethans wrote: 1. As it is impossible to do use XXX as NativeClass we get to the snip extension (DateTime, DateTimeZone). However introducing the new class DateTimeSpan might break people's code that do things like: ?php use myNamespace::DateTimeZone as DateTimeZone; ? This is indeed the biggest problem. However, it only exists in the global namespace (non-namespaced code). An example script using the non-existing hypothetical PEAR2::DateTime class: ?php include 'PEAR2/Autoload.php'; use PEAR2::DateTime; // fatal error - use name conflicts with internal class $a = new DateTime; ? However, the answer is simple and elegant. PHP applications that take advantage of namespaces should use a namespace *in the application global code* that is reserved for application code, like __php__. ?php namespace __php__; include 'PEAR2/Autoload.php'; use PEAR2::DateTime; $a = new DateTime; // $a is an object of class PEAR2::DateTime after autoloading, or if a previously included file has declared class DateTime in namespace PEAR ? Note that the only difference here is the addition of 1 line of code at the top of the file. On the same token, this code: ?php namespace __php__; $a = new DateTime; // $a is an object of class ::DateTime ? works as expected, accessing the internal DateTime class directly. In other words, 1 line of code is needed to take advantage of namespace's full protection and ability to import conflicting class names into the global (in this case unqualified, not containing :: in the name) scope, while at the same time preserving BC with existing code (no modification needed beyond addition of namespace __php__;). I recommend that the manual specify this convention, and will happily take on the documentation of it. 2. You have to import every class yourself. You can currently not do: use myNamespace::* as *; // or similar syntax Actually, ::* would only be deterministic if use performed some kind of autoloading, it's not a question of runtime versus compile-time - it's simply not possible to determine which class is intended if more than one ::* is used unless the answer is determined by code loading, this is why Java/Python import actually loads code as well as aliasing identifiers. There are ways of simulating use myNamespace::* as *; that are almost as complete and are actually better for long-term
[PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Hi Derick, I've been thinking a *lot* about your provocative email in the past couple of days, and have come to a different conclusion from my original reply (which, as a reminder stated I saw no problem with removing namespaces as long as we kept the import facility to alias classes via use). After a few hours of thinking practically about the implementation, I realized that this would be impossible for the same reasons as your first argument. So, I set out to find a solution that keeps namespaces and solves the problems. I have found the solutions to every problem I could find, and to my surprise, even after crafting a new patch to solve some of them, have found a way to solve all of the problems within the existing implementation (with a few tweaks, but nothing major changed) or by specifying new coding conventions. Summary: 1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. 2) use Name::*; is technically impossible without some kind of autoloading mechanism, but can be reasonably approximated by importing a long namespace name as a shorter one. use PEAR2::Really::Long::Name as a; then allows referring to PEAR2::Really::Long::Name::Classname as a::Classname, and PEAR2::Really::Long::Subnamespace::Classname as a::Subnamespace::Classname. 3) multiple namespaces per file should be allowed, but strongly discouraged as a coding practice of last resort for most users. 4) brackets for namespaces is most necessary for hierarchical namespace implementations. This is not such an implementation, and as such brackets do not add clarity but do slow down the implementation. 5) namespaces provide these benefits that are not available in PHP: a) short, unqualified descriptive class names can be used without fear of conflicting with an internal class b) a clear, uniform coding convention on how to avoid conflicts between your code and others that will help those who have to maintain the code of others. c) a way to alias longer names to increase readability and maintainability of code. 6) There are some dangers when using namespaces with autoload, but simple ways of thwarting those dangers. Also dangerous is trusting external code that is in the same namespace, as functions can be redefined. Detailed answers: Derick Rethans wrote: 1. As it is impossible to do use XXX as NativeClass we get to the snip extension (DateTime, DateTimeZone). However introducing the new class DateTimeSpan might break people's code that do things like: ?php use myNamespace::DateTimeZone as DateTimeZone; ? This is indeed the biggest problem. However, it only exists in the global namespace (non-namespaced code). An example script using the non-existing hypothetical PEAR2::DateTime class: ?php include 'PEAR2/Autoload.php'; use PEAR2::DateTime; // fatal error - use name conflicts with internal class $a = new DateTime; ? However, the answer is simple and elegant. PHP applications that take advantage of namespaces should use a namespace *in the application global code* that is reserved for application code, like __php__. ?php namespace __php__; include 'PEAR2/Autoload.php'; use PEAR2::DateTime; $a = new DateTime; // $a is an object of class PEAR2::DateTime after autoloading, or if a previously included file has declared class DateTime in namespace PEAR ? Note that the only difference here is the addition of 1 line of code at the top of the file. On the same token, this code: ?php namespace __php__; $a = new DateTime; // $a is an object of class ::DateTime ? works as expected, accessing the internal DateTime class directly. In other words, 1 line of code is needed to take advantage of namespace's full protection and ability to import conflicting class names into the global (in this case unqualified, not containing :: in the name) scope, while at the same time preserving BC with existing code (no modification needed beyond addition of namespace __php__;). I recommend that the manual specify this convention, and will happily take on the documentation of it. 2. You have to import every class yourself. You can currently not do: use myNamespace::* as *; // or similar syntax Actually, ::* would only be deterministic if use performed some kind of autoloading, it's not a question of runtime versus compile-time - it's simply not possible to determine which class is intended if more than one ::* is used unless the answer is determined by code loading, this is why Java/Python import actually loads code as well as aliasing identifiers. There are ways of simulating use myNamespace::* as *; that are almost as complete and are actually better for long-term maintenance. For instance, let's say you want to use several classes from PEAR2::Ultra::Long::Package::Name. You don't need to use each class
Re: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Holy wow. That was fantastic! Not to downplay anything that Stas and the other developers have done -- because let's face it, they've done a fantastic job themselves -- you have definitely risen above and beyond the call of duty and really come up with some very compelling counter-arguments. This really makes me look forward to using namespaces, and to reading your guides. Thank you for all of the time and effort you, and those who have spent time helping you, have put into this feature. :)
RE: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Hi Greg, Thanks for the detailed thoughts. Guides examples regarding use-cases will definitely be important for the community. I am sure just this email has already been very helpful to many on this list. Andi -Original Message- From: Gregory Beaver [mailto:[EMAIL PROTECTED] Sent: Thursday, December 06, 2007 5:36 PM To: Derick Rethans Cc: PHP Developers Mailing List Subject: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace Hi Derick, I've been thinking a *lot* about your provocative email in the past couple of days, and have come to a different conclusion from my original reply (which, as a reminder stated I saw no problem with removing namespaces as long as we kept the import facility to alias classes via use). After a few hours of thinking practically about the implementation, I realized that this would be impossible for the same reasons as your first argument. So, I set out to find a solution that keeps namespaces and solves the problems. I have found the solutions to every problem I could find, and to my surprise, even after crafting a new patch to solve some of them, have found a way to solve all of the problems within the existing implementation (with a few tweaks, but nothing major changed) or by specifying new coding conventions. Summary: 1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. 2) use Name::*; is technically impossible without some kind of autoloading mechanism, but can be reasonably approximated by importing a long namespace name as a shorter one. use PEAR2::Really::Long::Name as a; then allows referring to PEAR2::Really::Long::Name::Classname as a::Classname, and PEAR2::Really::Long::Subnamespace::Classname as a::Subnamespace::Classname. 3) multiple namespaces per file should be allowed, but strongly discouraged as a coding practice of last resort for most users. 4) brackets for namespaces is most necessary for hierarchical namespace implementations. This is not such an implementation, and as such brackets do not add clarity but do slow down the implementation. 5) namespaces provide these benefits that are not available in PHP: a) short, unqualified descriptive class names can be used without fear of conflicting with an internal class b) a clear, uniform coding convention on how to avoid conflicts between your code and others that will help those who have to maintain the code of others. c) a way to alias longer names to increase readability and maintainability of code. 6) There are some dangers when using namespaces with autoload, but simple ways of thwarting those dangers. Also dangerous is trusting external code that is in the same namespace, as functions can be redefined. Detailed answers: Derick Rethans wrote: 1. As it is impossible to do use XXX as NativeClass we get to the snip extension (DateTime, DateTimeZone). However introducing the new class DateTimeSpan might break people's code that do things like: ?php use myNamespace::DateTimeZone as DateTimeZone; ? This is indeed the biggest problem. However, it only exists in the global namespace (non-namespaced code). An example script using the non-existing hypothetical PEAR2::DateTime class: ?php include 'PEAR2/Autoload.php'; use PEAR2::DateTime; // fatal error - use name conflicts with internal class $a = new DateTime; ? However, the answer is simple and elegant. PHP applications that take advantage of namespaces should use a namespace *in the application global code* that is reserved for application code, like __php__. ?php namespace __php__; include 'PEAR2/Autoload.php'; use PEAR2::DateTime; $a = new DateTime; // $a is an object of class PEAR2::DateTime after autoloading, or if a previously included file has declared class DateTime in namespace PEAR ? Note that the only difference here is the addition of 1 line of code at the top of the file. On the same token, this code: ?php namespace __php__; $a = new DateTime; // $a is an object of class ::DateTime ? works as expected, accessing the internal DateTime class directly. In other words, 1 line of code is needed to take advantage of namespace's full protection and ability to import conflicting class names into the global (in this case unqualified, not containing :: in the name) scope, while at the same time preserving BC with existing code (no modification needed beyond addition of namespace __php__;). I recommend that the manual specify this convention, and will happily take on the documentation of it. 2. You have to import every class yourself. You can currently not do: use myNamespace::* as *; // or similar syntax Actually, ::* would only be deterministic if use performed some kind
Re: [PHP-DEV] A rebuttal to Re: RFC: Dropping Namespace
Hi Greg, I'm speechless. All of your points are sound and you've obviously done your homework, here. I agree with Ken in that you've gone above and beyond on the research and arguments you've presented here. Excellent work and a hearty +1 to all of your points. Jeremy Gregory Beaver wrote: Hi Derick, I've been thinking a *lot* about your provocative email in the past couple of days, and have come to a different conclusion from my original reply (which, as a reminder stated I saw no problem with removing namespaces as long as we kept the import facility to alias classes via use). After a few hours of thinking practically about the implementation, I realized that this would be impossible for the same reasons as your first argument. So, I set out to find a solution that keeps namespaces and solves the problems. I have found the solutions to every problem I could find, and to my surprise, even after crafting a new patch to solve some of them, have found a way to solve all of the problems within the existing implementation (with a few tweaks, but nothing major changed) or by specifying new coding conventions. Summary: 1) recommend all global non-namespaced code that wishes to import namespaced code via use Namespace::Classname add a namespace __php__; at the top of the file, and that the __php__ namespace be reserved for use by end-user applications. 2) use Name::*; is technically impossible without some kind of autoloading mechanism, but can be reasonably approximated by importing a long namespace name as a shorter one. use PEAR2::Really::Long::Name as a; then allows referring to PEAR2::Really::Long::Name::Classname as a::Classname, and PEAR2::Really::Long::Subnamespace::Classname as a::Subnamespace::Classname. 3) multiple namespaces per file should be allowed, but strongly discouraged as a coding practice of last resort for most users. 4) brackets for namespaces is most necessary for hierarchical namespace implementations. This is not such an implementation, and as such brackets do not add clarity but do slow down the implementation. 5) namespaces provide these benefits that are not available in PHP: a) short, unqualified descriptive class names can be used without fear of conflicting with an internal class b) a clear, uniform coding convention on how to avoid conflicts between your code and others that will help those who have to maintain the code of others. c) a way to alias longer names to increase readability and maintainability of code. 6) There are some dangers when using namespaces with autoload, but simple ways of thwarting those dangers. Also dangerous is trusting external code that is in the same namespace, as functions can be redefined. Detailed answers: Derick Rethans wrote: 1. As it is impossible to do use XXX as NativeClass we get to the snip extension (DateTime, DateTimeZone). However introducing the new class DateTimeSpan might break people's code that do things like: ?php use myNamespace::DateTimeZone as DateTimeZone; ? This is indeed the biggest problem. However, it only exists in the global namespace (non-namespaced code). An example script using the non-existing hypothetical PEAR2::DateTime class: ?php include 'PEAR2/Autoload.php'; use PEAR2::DateTime; // fatal error - use name conflicts with internal class $a = new DateTime; ? However, the answer is simple and elegant. PHP applications that take advantage of namespaces should use a namespace *in the application global code* that is reserved for application code, like __php__. ?php namespace __php__; include 'PEAR2/Autoload.php'; use PEAR2::DateTime; $a = new DateTime; // $a is an object of class PEAR2::DateTime after autoloading, or if a previously included file has declared class DateTime in namespace PEAR ? Note that the only difference here is the addition of 1 line of code at the top of the file. On the same token, this code: ?php namespace __php__; $a = new DateTime; // $a is an object of class ::DateTime ? works as expected, accessing the internal DateTime class directly. In other words, 1 line of code is needed to take advantage of namespace's full protection and ability to import conflicting class names into the global (in this case unqualified, not containing :: in the name) scope, while at the same time preserving BC with existing code (no modification needed beyond addition of namespace __php__;). I recommend that the manual specify this convention, and will happily take on the documentation of it. 2. You have to import every class yourself. You can currently not do: use myNamespace::* as *; // or similar syntax Actually, ::* would only be deterministic if use performed some kind of autoloading, it's not a question of runtime versus compile-time - it's simply not possible to determine which class is intended if more than one ::* is used unless the answer is determined by code loading, this is why Java/Python import