Stanislav Malyshev wrote:
>> <?php
>> namespace Foo;
>> throw new Exception;
>>
>> In this case PHP first looks for Foo::Exception and only then for
>> internal
>> Exception, but the first lookup may call __autoload (or corresponding SPL
>> functions) and it can emit error or throw exception.
>>
>> The patch provides an additional boolean argument to __autoload() that
>> say
>> if class is really required. In case if it false, user code shouldn't
>> emit
>> errors or throw exceptions.
> 
> There's two problems here:
> 1. On each access to internal class, like Exception, SPL classes,
> DateTime, reflection classes, etc. - we'd have call to autoload and
> subsequent disk access, maybe more than one if we have include path.
> Performance of it would be awful.

This is a problem, agreed.

> 2. All libraries having autoloaders would have to rewrite them to
> support the new mode.

This is not an issue - won't they have to support
Class::Names::Like::This anyways?  Backwards compatibility has already
been broken.

> I would propose different solution. When we have unresolved unqualified
> name, we do the following:
> 1. Check if we already know such class in namespace at compile-time. If
> so, it's resolved.
> 2. If not, will be resolved at run-time.
> 3. At run-time, check if we know such class in namespace now. If yes,
> it's resolved.
> 4. If not, check if we know internal class with such name. If yes, it's
> resolved to internal class.
> 5. If not, try to autoload this class. If autoloading fails, it's the
> undefined class error.

The problem is that with this autoload technique this code now throws an
Exception rather than a Foo::Exception:

Foo/Exception.php:
<?php
namespace Foo;
class Exception extends ::Exception {}
?>

Foo/Something.php:
<?php
namespace Foo;
function __autoload($class)
{
    include str_replace('::', '/', $class) . '.php';
}

class Something
{
    function __construct($param)
    {
        if ($param == 3) {
            throw new Exception('oops');
        }
    }
}
$a = new Something(3);
?>

This would mean that all naming conflicts with internal classes must
have a different import or be fully qualified.

However, I wonder if using an import would be a clever way to get around
the problem?

Foo/Something.php:
<?php
namespace Foo;
import Foo::Exception;
function __autoload($class)
{
    include str_replace('::', '/', $class) . '.php';
}

class Something
{
    function __construct($param)
    {
        if ($param == 3) {
            throw new Exception('oops');
        }
    }
}
$a = new Something(3);
?>

As I understand it, this would make the file act as if we had written it
like:

Foo/Something.php:
<?php
function __autoload($class)
{
    include str_replace('::', '/', $class) . '.php';
}

class Foo::Something
{
    function __construct($param)
    {
        if ($param == 3) {
            throw new Foo::Exception('oops');
        }
    }
}
$a = new Foo::Something(3);
?>

If this is indeed the case, then it would satisfy my concerns with the
patch and would simply be up to the documentation team to document this
gotcha.

Greg

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

Reply via email to