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

Reply via email to