Hello All,
There is no way around it given the feedback I am seeing about
namespace usage in the wild, to warm up this old post again.
This post and the additional commentary, especially about performance
by Stas can be found in the archives at:
http://marc.info/?l=php-internals&m=121527668606247
I think given the feedback from users, we really need to actually
benchmark the performance slow down that Greg's proposed changes will
bring. I also guess there are two types of users out there:
1) those that tend to always spice up their API's by wrapping pretty
much all internal functionality (be if that the internal functionality
has a procedural or an OO API). These are also the people that will
have the more complex OO structures (deep inheritance). They also seem
like the most heavy users of namespaces
2) those that keep their structures flat, use native API's directly
and live in a mixed world of OO and procedural code
So while we are assessing the impact its important to keep in mind
which user type is going to be affected in what way. Furthermore I
hope that some of the people that have build up a code base that uses
namespaces will do this benchmarking, because otherwise we will hardly
get any useful data. Even then of course the benchmarks must be taken
with a grain of salt (as always).
I am including the email from Greg at the bottom here, along with a
reply from Stas (again read the archive to get the full story). Maybe
if we think hard about this one (now that we know that its an
important real world need), we can discover a solution that we did not
see at first.
On 05.07.2008, at 18:48, Greg Beaver wrote:
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.
On 17.07.2008, at 19:57, Stanislav Malyshev wrote:
In other words, with the current implementation, you can just do
"use Foo::Exception;" and it works, but if you *forget* to do the
use statement, you can get unpredictable behavior with no warning
until your
You get previctable behavior in all cases, there's no randomness in
the engine.
to "use ::Exception", then your code is simply slightly slower (1
extra call to autoload if it exists), but still works properly. It
also tilts
It's not slightly slower, it's *A LOT* slower - exhaustive search of
whole include path for *EACH* call mentioning internal class. That
means you have to declare *EACH* internal class - even if no clashes
ever existed - for *EACH* use. Basically, it's the same as always
using ::Class only implemented in a way that its disastrous effects
are hidden until you check performance of your code. Then you have
to go back and add use statement for each internal class in each of
your files. Lot's of fun that would be.
regards,
Lukas Kahwe Smith
[EMAIL PROTECTED]
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php