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