Lukas Kahwe Smith wrote:
Aloha,

Since Johannes has been stumped (and therefore not as visible as he would have hoped) with work and 5.3 CVS is already filled brim with awesome new features, I have been approached by several people wondering how we can speed up the process. I have always said I am available to play the secretary to the RM, but in order to ensure that developers have a greater chance of having an RM to talk to, Johannes agreed to move me to co-RM status.

glad to hear it!

1) namespaces
Here we need to make sure that the current state is now in a coherent state. I think Derick still has some issues [3] with the recent change by Greg [4], but even his criticism did not sound all to loud. So I think we are in a good state here?

My recent changes aside, there are still some fubar issues with name resolution, and there has been some offlist discussion of ways to fix this that have not led to concrete onlist proposals yet.

For those who don't know what I'm talking about, the question is how to resolve an unqualified classname inside a namespace. i.e. this code:

a.php:
<?php
namespace Foo;
throw new Exception('is this Foo::Exception or ::Exception?');
?>

Currently, the above code would throw ::Exception, because if a namespaced class does not exist, internal classes are checked before autoloading for performance reasons. However, if we execute this code instead:

b.php:
<?php
namespace Foo;
class Exception {}
include 'a.php';
?>

then a.php would throw Foo::Exception. In other words, depending on file inclusion order, classnames can change with current PHP accepted practices. The solution to this is to use each namespaced class explicitly:

a2.php:
<?php
namespace Foo;
use Foo::Exception;
throw new Exception('this is Foo::Exception always');
?>

However, all it takes is one forgotten "use" statement, and a very subtle bug could be introduced later.

Taking a step back, let's examine why autoload is not called before checking internal classes - it is for performance reasons. However, this performance enhancement causes unpredictable behavior *by default* without explicit action.

There is a simple solution, however. If one changes the name resolution to this pseudo-code:

1) check Foo::Exception for existence
2) if not found, try to autoload Foo::Exception
3) if not found, check for ::Exception existence, userspace *or* internal (addition of userspace check also fixes other problems raised on-list)
4) if not found, fail.

This fixes the logic problem, and re-introduces the performance slowdown for internal classes. FORTUNATELY there is a simple solution to this, which is to "use" all global classes:

<?php
namespace Foo;
use ::ArrayIterator;
$a = new ArrayIterator(array(1,2,3));
?>

The above code works exactly the same as:

<?php
namespace Foo;
$a = new ArrayIterator(array(1,2,3));
?>

and short-circuits the name resolution to:

1) check ::ArrayIterator for existence
2) if not found, fail.

To summarize, we should scrap the "performance enhancement" that introduces the potential for subtle and dangerous logic errors in name resolution because it is still possible to achieve that performance enhancement through one-time "use" of internal classnames.

With these changes, namespace classname resolution will be 100% deterministic regardless of file load order, it will still be possible to override internal classnames with userspace classes, and for the ultra-performance hungry, it is still easy to achieve faster classname resolution for internal classes. Win-win.

Greg

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to