Hi,
I suppose since I use autoload and classes I belong to the first group.
Thing is, we still do care about performance.
I currenly use underscores as some other programmers do, to "fake"
namespaced identifiers, and from my tests and this discussion so far I'm
convinced the namespaces as they are right now would cause more troubles
than they solve.
Automating name resolution at runtime is bound to have problems as PHP was
never intended to go up in "scopes" and resolve variables, this is why we
have "use" in closures, and why we have "global" in methods and functions.
One of the things I suggested few months ago was that runtime resolution is
simply not included at all, and that we have a syntax for explicitly
specifying the global namespace, when the code is inside a namespace. I
heard lots of objections how ugly it is to prepend everything with "::" (not
that this is the only possibly syntax), but it increasingly is becoming
apparent that the automatic resolution is bound to have either bug-prone or
performance issues, so why introduce a "trap" in the language that people
will continuosly fall into?
Running the autoloader before every internal class would be just amazing for
those of us with caching crawlers (directory crawls for classes and stores
location in cache). I'll be having cache miss every time I use an internal
class, which with larger class libraries can run into 2-3 seconds at a time
to look for, say, class ArrayObject.
The other solution to put autoload last is equally bad as it means an
internal class would override one of mine, which I autoload, making the
autoloader useless.
So I'd say, make it explicit and remove the vague moment.
Regards,
Stan Vassilev
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
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php