Re: RFC: Dropping Namespace

From: Date: Fri, 14 Dec 2007 02:58:06 +0000
Subject: Re: RFC: Dropping Namespace
References: 1 2 3 4  Groups: php.internals php.internals 
Request: Send a blank email to internals+get-34029@lists.php.net to get a copy of this message
Greg, I've been thinking about this as well and I also concluded that #3 is the way to go. If I "use" a class with the same name as an internal one, then I want to reference that class, I don't care about the internal class, and I don't want an error either. If a new PHP internal class is added to the future, then having the option of overriding internal class names guarantees me that my code won't break in an upgrade. If at the time of writing my code, I know that I am "using" a class with the same name as an internal one, AND I need to use both, then I can alias the classes appropriately to avoid clashes, e.g. Zend/Exception.php <?php namespace Zend; class Exception extends ::Exception { // ... }; ?> test1.php <?php use Zend::Exception; throw new Exception( 'Zend exception occurred' ); ?> test2.php <?php use Zend::Exception as ZendException; if( $someCondition )
    throw new ZendException( 'Zend exception occurred' );
else
    throw new Exception( 'unknown generic exception' );
?> Regards, Jessie Gregory Beaver wrote:
Dangit, I wasn't finished when that sent (apparently Ctrl-S sends a message - I was trying to Ctrl-V to paste) Gregory Beaver wrote:
Hi again, I am not sure this will make it through the noise *sigh* but I'll give a try :) Derick Rethans wrote:
Hei, now some patches by Greg and Dmitry made it into CVS, some of the things in my mail have been resolved, however, we still need to come up with a solution to the 1st and most important issue: On Tue, 4 Dec 2007, Derick Rethans wrote:
    
1. As it is impossible to do "use XXX as NativeClass" we get to the point where we'd have to namespace new internal native classes
otherwise we might introduce BC breaks. AFAIK, we've always said that PHP reserves the globals space for it's own use (see also: http://www.php.net/manual/en/userlandnaming.rules.php). In case we do add new classes (an example could be DateTimeSpan), they should of course follow the same format as already existing classes in the extension (DateTime, DateTimeZone). However introducing the new class DateTimeSpan might break people's code that do things like: <?php use myNamespace::DateTimeZone as DateTimeZone; ?> feature versions of people would then show: Fatal error: Cannot use myNamespace::DateTimeZone as DomDocument because the name is already in use. It would be silly to require to have to do this: - Create a class PHP::Date::TimeSpan - In your scripts: use PHP::Date::TimeSpan But with the current implementation, this seems to be the only non-BC breaking solution. If we chose *not* to require this silly namespacing of internal classes, users instead have to do this: <?php use myNamespace::DateTimeZone as myDateTimeZone; ?> Basically prefixing the classnames... This you can already do just fine without namespaces.
          
I know Greg has some ideas with __php__ as recommendation, but I find it a bit clumsy still. Perhaps Greg can summarize how it will address the above issue?
I've been thinking quite a bit about several suggestions (surprise surprise). First of all, Marcus Boerger suggested on IRC that "__php__" was not the best name, and proposed "__user__" as a more logical choice for the convention, which appeals to me more for the obvious reason that it doesn't have the chance of confusing with "PHP" or "php" should either of these be adopted by the core folks ever. I am going to use some shorthand. "internal class is used first" means this code: <?php namespace hithere; $a = new Exception('hi'); ?> would use ::Exception unles hithere::Exception already exists. In my inimitable style, for the larger suggestions I've been thinking about I will list them: 1) having an implicit namespace for unnamespaced code 2) never accessing internal classes inside a namespace (tough to summarize I explain below) 3) allowing override of internal classes with "use" in the global scope 4) keep things the way they work now, and recommend using "namespace __user__" for userspace code. 1) having an implicit namespace for unnamespaced code ===================== This is an interesting idea that will break autoloaders unless the implicit namespace is automatically stripped on a call to autoload, get_class() and reflection. Pros: use myNamespace::DateTimeZone as DateTimeZone; will always work as intended Cons: slight performance hit on every autoload caused by a strstr() check on classname for "__auto__::" and same hit on get_class(), ReflectionClass stuff large number of potential "oops" spots for the implicit namespace to slip into code and break everything horrendously. the patch would be huge and very dangerous for the above reason until kinks are worked out. doesn't solve the "internal class is used first" issue. 2) never accessing internal classes inside a namespace ===================== This basically means changing the autoloading rules to the following (using the hithere namespace/Exception example from above): 1) does hithere::Exception exist? 2) if not, autoload it Pros: it is not necessary to "use hithere::classname" for every class you might autoload. 1 hash lookup reduced per autoloaded class (very minor performance gain, hash lookup is O(1). profiling might not even detect a difference.) Cons: to use internal classes, you would need to explicitly use ::Classname; for each of them. Code that does not use autoload would *also* have to explicitly use ::Classname; code that uses internal classes that wishes to become namespaced would need to go through and figure out which internal classes are used and add "use ::Classname" at the top of the file, making porting to namespaces much more difficult. 3) allowing override of internal classes with "use" in the global scope ===================== This would be surprisingly easy to implement, currently the only thing preventing it from happening is a 5-10 line check in zend_do_use() to see if the name requested would conflict with an internal class. Remove that check and it becomes possible Pros: Derick's main issue goes away, name conflicts with internal classes are never possible when "use"ing them it becomes possible to change which class is used in a file with 1 line of code: <?php use myNamespace::Exception as Exception; ?> As opposed to two: <?php namespace __user__; use myNamespace::Exception as Exception; ?> Cons: It is then possible to accidentally override an internal classname used in the code. it encourages continuing to declare classes/functions in the global namespace, resulting in potential name conflicts a la "Date"
4) keep things the way they work now, and recommend using "namespace __user__" for userspace code. Pros: explicit declaration of namespace can make code clearer Cons: users using global namespace and "use" will get burned. ========= As a reality check, in the entire lifetime of PHP, there has been only 1 name collision between new PHP classes and pre-existing major classnames. SplFileInfo was originally a conflict, but that was solved with a simple prefix to the classname of "Spl." This is an issue, but until PHP starts adding billions of classes to handle core elements, it is not a large one. However, it can be easily and simply solved, so I say why not :). After enumerating the pros/cons of each point, my personal opinion is that #1 and #2 are not feasible from either a user or a core developer standpoint, and would create more problems than they would solve. #3, however, looks much more appealing than I thought it would. I think this is a good idea as an addition. I might be inclined to ask for an E_STRICT warning that "use My::Exception;" is overriding an internal class, but that's up to what you all think. Implementing #3 would remove the con of #4. To answer Derick's call for clarification on #4, The convention of using the __user__ namespace for all code that uses namespaced code would force users to do two things: 1) explicitly "use" classnames they wish to shorten by importing them from another namespace 2) add "namespace __user__" to the top of their files. These two things would mean 1) autoload always works as intended 2) classes from external projects (dependencies not found in the current file) are always documented prominently at the top of the file, increasing maintainability if the project passes on to another developer. 3) the presence of "namespace __user__" would also immediately document the fact that this code is intended to be executed and is not library code (does not declare classes/functions and only uses them) Point #1 does not matter to people who don't use autoload, but #2 and #3 both increase the ease of understanding the purpose of code. I've often had trouble sifting through source code to find the main files that are executed. If I could have done a simple "grep -e namespace __user__" it would make things a lot easier that way. Thanks, Greg


« previous php.internals (#34029) next »