Lukas Kahwe Smith wrote:
> 
> On 04.11.2008, at 17:15, Gregory Beaver wrote:
> 
>> In other words, it is perfectly all right to have a different name
>> resolution for classes than we have for functions and constants because
>> of this different expectation.  It is dangerous to fallback for classes
>> prior to autoload, but it is not at all dangerous for
>> functions/constants because the expectation is different.
> 
> To me the key question is do we want to let people overload global
> classes easily or are we mostly talking about convinience? Class names
> are typed quite seldom (and even in a few years down the road the bulk
> of PHP's features will be provided via functions), so I would not think
> that we really need to focus on convenience here.

OK, taking a step back.  Let's distill the two problems we're trying to
solve

1) namespaces provide encapsulation - a safe way to name things without
worrying about whether it will conflict with external code
2) accessing internal functionality - the most used stuff in PHP should
still be easy to use in namespaces.

#1 means that when using our code inside namespaces, when there is
ambiguity we want it to look for namespaced stuff first and foremost.
#2 means we want to be able to access stuff like strlen() and
array_map() without any monkey business.

The largest conflict between #1 and #2 happens with classes because of
autoload.  __autoload() is expensive from a performance standpoint, and
should not be called unnecessarily.

I posit that the most used stuff in PHP are internal functions (not
global userspace functions, not internal classes, not userspace classes)
and so this needs to be a priority.  In addition, there is already
confusion over things like:

<?php
// which of these is a function?
$a = 1;
unset($a);
$a = key(array('hi' => 1));
include('oops.php');
?>

so requiring a prefix for functions will lead to parse errors in user
code like:

<?php
\include('oops.php');
?>

so the best resolution for functions is:

1) ns\function
2) internal function

Classes are different (TM).

if we do:

1) ns\class
2) autoload ns\class
3) internal class

then this code has hidden performance hits:

<?php
namespace foo;
include 'external_autoload.php';  // __autoload must be declared
unnamespaced
$a = new ArrayObject(array('hi')); // calls autoload unnecessarily
?>

if we really mean the "ArrayObject" class and not the "foo\ArrayObject"
class.  Thus, the convenience of internal fallback has disadvantages
(major performance problems) that do not exist with functions or constants.

Notifying the user via E_NOTICE/E_STRICT/E_WHATEVER simply adds
annoyance, and introduces potential for behavior change.  For instance,
if a user decides to start using some external library that defines an
autoload when they didn't have it before, suddenly all of their code
throws E_NOTICEs every time an internal class name is referenced.  Or,
without the E_NOTICE, performance suddenly slows way down and the user
blames the external library.

If we do:

1) ns\class
2) internal class
3) autoload ns\class

then our code example fails in a more subtle way.  The ambiguity of
"ArrayObject" resolves always in favor of internal class ArrayObject,
which means that users have to always explicitly import namespaced
classes to avoid this problem.  Why is it a problem?

Let's say we're doing our own userspace implementation of PDO with a few
extensions, for a system where PDO is disabled:

<?php
namespace Myproject;
class PDO {} // userspace implementation of PDO
?>

now in another file:

<?php
namespace Myproject;
$a = new PDO(...);
?>

[note: this implementation depends on __autoload existing]

Now, if PDO extension is disabled, the above code will successfully
autoload Myproject\PDO.  Imagine that on an upgrade, PDO is enabled.
Now, the object instantiated is of class PDO, not Myproject\PDO.
Suddenly, there are subtle logic errors that creep in (not a fatal
error), but the code continues to operate normally.

This resolution is very dangerous, and is a clear violation of the
primary purpose of namespaces.

If we do this:

1) ns\class
2) autoload ns\class

we get a "stronger" E_NOTICE (fatal E_ERROR) when an internal class is
used without explicit import.  This is robust, easy to debug, and forces
good code without much pain.  Our example user above has no problems
with the external library, and changes need not be made after initial
coding.

By doing the resolution I've suggested (and Stas, incidentally, was the
first to suggest this):

classes:
1) ns\class
2) autoload ns\class
3) FAILBOAT

functions/constants:
1) ns\func or ns\const
2) internal func\const
3) FAILBOAT

We get the best of #1 and the best of #2, and it makes coding easier in
the long run.

Greg

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

Reply via email to