# Namespaces and __autoload()

- Thread: https://externals.io/message/31927
- Original archive: https://news-web.php.net/php.internals/31927
- Started by Dmitry Stogov on 2007-08-27T06:15:03+00:00
- Messages: 8
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #31927 — Dmitry Stogov — 2007-08-27T06:15:03+00:00

URL: https://externals.io/message/31927#31927

Hi,

Please look into patch that implements __autoload() support for namespaces.
The patch touches not only ZE but also SPL.

In the following code we cannot exactly know if "Exception" class is from
current namespace or it is an internal PHP class.

<?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.

I am going to commit the patch on Wednesday.

It is the last semantic patch for namespaces we have.
After its commit we are going to look into syntax problems (namespace or
package, brackets, import or using, ...).

Thanks. Dmitry.

---

## #31941 — Stanislav Malyshev — 2007-08-27T17:49:22+00:00

URL: https://externals.io/message/31927#31941 · In reply to: #31927

> <?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.
2. All libraries having autoloaders would have to rewrite them to 
support the new mode.

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.

This rule is a bit more complex, but allows to resolve common cases 
without extra filesystem accesses and allows to keep autoloader without 
modification.

Comments?
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #31948 — Gregory Beaver — 2007-08-27T22:36:37+00:00

URL: https://externals.io/message/31927#31948 · In reply to: #31941

Stanislav Malyshev wrote:
> > […]
> 
> 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

---

## #31949 — Stanislav Malyshev — 2007-08-27T22:42:18+00:00

URL: https://externals.io/message/31927#31949 · In reply to: #31948

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

Yep, unless you do require 'Foo/Exception.php'. Yes, I know it's not as 
nice as it might be. But the alternative is either use :: always or say 
goodbye to performance.

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

It would solve the issue too, of course.
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #31951 — Derick Rethans — 2007-08-28T07:43:41+00:00

URL: https://externals.io/message/31927#31951 · In reply to: #31927

> 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.

It looks like this is going to break BC. Are current autoload functions 
guaranteed to work with the new implementation?

Derick

-- 
Derick Rethans
http://derickrethans.nl | http://ez.no | http://xdebug.org

---

## #31954 — dz@bitxtender.com — 2007-08-28T12:14:06+00:00

URL: https://externals.io/message/31927#31954 · In reply to: #31941

Why don't we add an optional second argument to __autoload() that  
receives the fully qualified namespace name of the class that should  
be autoloaded? That doesn't break BC and it prevents conflicts.


David


Am 27.08.2007 um 19:49 schrieb Stanislav Malyshev:

> > […]
>
> 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.
> 2. All libraries having autoloaders would have to rewrite them to  
> support the new mode.
>
> 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.
>
> This rule is a bit more complex, but allows to resolve common cases  
> without extra filesystem accesses and allows to keep autoloader  
> without modification.
>
> Comments?
> -- 
> Stanislav Malyshev, Zend Software Architect
> stas@zend.com   http://www.zend.com/
> (408)253-8829   MSN: stas@zend.com

---

## #31955 — Stanislav Malyshev — 2007-08-28T16:31:05+00:00

URL: https://externals.io/message/31927#31955 · In reply to: #31954

> Why don't we add an optional second argument to __autoload() that 
> receives the fully qualified namespace name of the class that should be 
> autoloaded? That doesn't break BC and it prevents conflicts.

The first argument already receives that, why would you need the second one?
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #32092 — francois.laupretre@ratp.fr — 2007-09-07T15:19:47+00:00

URL: https://externals.io/message/31927#32092 · In reply to: #31927

Hi,

> From: Dmitry Stogov [mailto:dmitry@zend.com] 
> 
> 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.

Actually, an autoload handler should never emit errors or throw exceptions. With handlers registered through SPL, it is already the case. When using an __autoload() functions, raising an error when a symbol is not found is useless because we know that the PHP interpreter will do it. So, I propose to have PHP ignore any error or exception raised from autoload handlers. This would make the additional argument useless.

Actually, I also wanted to add a second argument to autoload handlers. It would give the type of the symbol we are looking for. Today, we are unable to know if we are searching for a class or an interface. So, an autoload handler like PHK's has to try both. It is not very important because most existing autoload handlers are so primitive (generally filename-based) that they treat both the same way. But, in the future, if we extend autoloading to functions and constants, we will need this argument. I cannot work on that now but, as you are considering modifying the autoload handler arguments, I thought you could be interested.

Regards

Francois
