# Idea for namespace lookup resolution

- Thread: https://externals.io/message/33960
- Original archive: https://news-web.php.net/php.internals/33960
- Started by Jessie Hernandez on 2007-12-12T05:45:09+00:00
- Messages: 5
- 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

---

## #33960 — Jessie Hernandez — 2007-12-12T05:45:09+00:00

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

I just thought of something that might be a solution to the lookup rules 
that we currently have in the namespaces implementation. Whether it's 
good or not, I just wanted to throw it out there. Here goes:

Support a user-defined function named __get_namespace_classes, which 
will be similar to __autoload. The signature of the function would be 
the following:


array __get_namespace_classes(string $namespaceName);

Returns an array of names of classes that are under the specified 
namespace, or `FALSE` if the classes under the namespace could not be 
determined.


The above function would be used in the lookup rules as follows (using 
DateTime as an example):

1) Does the class DateTime exist in the current namespace?
2) If not, and the function __get_namespace_classes exists, call 
__get_namespace_classes.
3) If the string DateTime is returned in the array from 
__get_namespace_classes, then autoload that class.
4) If the class is not in the resulting array, or if the result was 
FALSE, then look for an internal class DateTime.


With the above function, you can define classes inside your namespace 
that are named the same as internal classes without having to explicitly 
"use" them all over the place. You also solve the problem of namespace 
imports (sorry, use :-) ):

<?php
use PEAR::Net::*;

$a = new FTP();

// The above "use" statement results in calling the
// __get_namespace_classes function and "using" each class in the
// resulting array internally. Meaning the above will be equivalent to
// this:
//
// use PEAR::Net::Curl;
// use PEAR::Net::DNS;
// use PEAR::Net::FTP;
// ...etc...
?>


For the above function to work best, the PHP "dir" function, as an 
example, should be modified to have an additional "use_include_path" 
argument:

object dir(string $directory [, bool $use_include_path])


By passing `TRUE` as the second argument, the directory will be searched 
for in the include path. The user can then do something like the 
following as an implementation of __get_namespace_classes (assuming the 
user organized it into class per file, as is common):

<?php
function __get_namespace_classes($namespaceName)
{
     $classes = false;
     $nsDir = str_replace( '::', DIRECTORY_SEPARATOR, $namespaceName );
     $d = dir( $nsDir, true );

     if( $d )
     {
         $classes = array();

         while( ( $file = $d->read() ) !== false )
             $classes[] = str_replace( '.php', '', $file );

         $d->close();
     }

     return $classes;
}
?>


Let me know what you think!



Regards,

Jessie

---

## #33961 — Gregory Beaver — 2007-12-12T06:32:49+00:00

URL: https://externals.io/message/33960#33961 · In reply to: #33960

Jessie Hernandez wrote:
> I just thought of something that might be a solution to the lookup rules
> that we currently have in the namespaces implementation. Whether it's
> good or not, I just wanted to throw it out there. Here goes:
> 
> Support a user-defined function named __get_namespace_classes, which
> will be similar to __autoload. The signature of the function would be
> the following:
> 
> 
> array __get_namespace_classes(string $namespaceName);
> 
> Returns an array of names of classes that are under the specified
> namespace, or `FALSE` if the classes under the namespace could not be
> determined.
> 
> 
> The above function would be used in the lookup rules as follows (using
> DateTime as an example):
> 
> 1) Does the class DateTime exist in the current namespace?
> 2) If not, and the function __get_namespace_classes exists, call
> __get_namespace_classes.
> 3) If the string DateTime is returned in the array from
> __get_namespace_classes, then autoload that class.
> 4) If the class is not in the resulting array, or if the result was
> FALSE, then look for an internal class DateTime.

This is of course a possibility, but it would be a tremendous
performance hit both in terms of memory and processing time.  The use
statements that specify dependencies are compile-time with minimal
memory consumption and no performance hit at all, not to mention they
only need be updated when using different classnames.

All of my experience in coding thus far says that the addition of a new
class to a file is exceedingly rare, and having to add that use line at
that point would not be any more difficult than it is to remember to use
a semi-colon or close matching "" or ().

I of course wouldn't stand in the way of this proposal if others think
it is the way to go, but there's no way I would use it or recommend it
as a coding practice for PEAR2.

Thanks,
Greg

---

## #34036 — Jessie Hernandez — 2007-12-14T16:19:39+00:00

URL: https://externals.io/message/33960#34036 · In reply to: #33960

Attached is the proof-of-concept patch. If the idea is met well, then 
I'll keep working on it to add caching and, if there's interest, I'll 
add *namespace imports*.

An example of how a class in a namespace that's named the same as an 
internal class can be loaded:

autoload.php
<?php
function __autoload($className)
{
     include_once str_replace( '::', DIRECTORY_SEPARATOR, $className ) . 
'.php';
}

function __get_namespace_classes($namespaceName)
{
     return array( 'Exception' );
}
?>

test.php
<?php
namespace ns;

include 'autoload.php';
$ex = new Exception();
var_dump( $ex ); // prints out ns:Exception instead of Exception
?>


I ran a few tests on it and did not find any significant performance 
hit. If possible, I'd like someone to try it out and see if they have 
the same result.

As always, comments/suggestions on the patch are welcome.


Regards,

Jessie Hernandez
Zend Certified Engineer (http://zend.com/zce.php?c=ZEND006359&r=222727282)


Jessie Hernandez wrote:
> I just thought of something that might be a solution to the lookup rules 
> that we currently have in the namespaces implementation. Whether it's 
> good or not, I just wanted to throw it out there. Here goes:
> 
> Support a user-defined function named __get_namespace_classes, which 
> will be similar to __autoload. The signature of the function would be 
> the following:
> 
> 
> array __get_namespace_classes(string $namespaceName);
> 
> Returns an array of names of classes that are under the specified 
> namespace, or `FALSE` if the classes under the namespace could not be 
> determined.
> 
> 
> The above function would be used in the lookup rules as follows (using 
> DateTime as an example):
> 
> 1) Does the class DateTime exist in the current namespace?
> 2) If not, and the function __get_namespace_classes exists, call 
> __get_namespace_classes.
> 3) If the string DateTime is returned in the array from 
> __get_namespace_classes, then autoload that class.
> 4) If the class is not in the resulting array, or if the result was 
> FALSE, then look for an internal class DateTime.
> 
> 
> With the above function, you can define classes inside your namespace 
> that are named the same as internal classes without having to explicitly 
> "use" them all over the place. You also solve the problem of namespace 
> imports (sorry, use :-) ):
> 
> <?php
> use PEAR::Net::*;
> 
> $a = new FTP();
> 
> // The above "use" statement results in calling the
> // __get_namespace_classes function and "using" each class in the
> // resulting array internally. Meaning the above will be equivalent to
> // this:
> //
> // use PEAR::Net::Curl;
> // use PEAR::Net::DNS;
> // use PEAR::Net::FTP;
> // ...etc...
> ?>
> 
> 
> For the above function to work best, the PHP "dir" function, as an 
> example, should be modified to have an additional "use_include_path" 
> argument:
> 
> object dir(string $directory [, bool $use_include_path])
> 
> 
> By passing `TRUE` as the second argument, the directory will be searched 
> for in the include path. The user can then do something like the 
> following as an implementation of __get_namespace_classes (assuming the 
> user organized it into class per file, as is common):
> 
> <?php
> function __get_namespace_classes($namespaceName)
> {
>     $classes = false;
>     $nsDir = str_replace( '::', DIRECTORY_SEPARATOR, $namespaceName );
>     $d = dir( $nsDir, true );
> 
>     if( $d )
>     {
>         $classes = array();
> 
>         while( ( $file = $d->read() ) !== false )
>             $classes[] = str_replace( '.php', '', $file );
> 
>         $d->close();
>     }
> 
>     return $classes;
> }
> ?>
> 
> 
> Let me know what you think!
> 
> 
> 
> Regards,
> 
> Jessie

---

## #34057 — Dmitry Stogov — 2007-12-17T09:45:42+00:00

URL: https://externals.io/message/33960#34057 · In reply to: #34036

Hi Jessie,

The namespace may include several files and it may be extended with 
additional files in any moment. So having single 
__get_namespace_classes() function will require to update it every time 
you extend namespace.

Also such function will significantly slowdown access to internal 
classes. (It was the main reason why __autoload() was moved after check 
for internal class).

Thanks. Dmitry.

Jessie Hernandez wrote:
> Attached is the proof-of-concept patch. If the idea is met well, then 
> I'll keep working on it to add caching and, if there's interest, I'll 
> add *namespace imports*.
> 
> An example of how a class in a namespace that's named the same as an 
> internal class can be loaded:
> 
> autoload.php
> <?php
> function __autoload($className)
> {
>     include_once str_replace( '::', DIRECTORY_SEPARATOR, $className ) . 
> '.php';
> }
> 
> function __get_namespace_classes($namespaceName)
> {
>     return array( 'Exception' );
> }
> ?>
> 
> test.php
> <?php
> namespace ns;
> 
> include 'autoload.php';
> $ex = new Exception();
> var_dump( $ex ); // prints out ns:Exception instead of Exception
> ?>
> 
> 
> I ran a few tests on it and did not find any significant performance 
> hit. If possible, I'd like someone to try it out and see if they have 
> the same result.
> 
> As always, comments/suggestions on the patch are welcome.
> 
> 
> Regards,
> 
> Jessie Hernandez
> Zend Certified Engineer (http://zend.com/zce.php?c=ZEND006359&r=222727282)
> 
> 
> Jessie Hernandez wrote:
> > […]

---

## #34069 — Jessie Hernandez — 2007-12-17T18:17:32+00:00

URL: https://externals.io/message/33960#34069 · In reply to: #34057

Dmitry,

As I mentioned, I did not find any significant performance penalty with 
this patch. Also, the patch can be improved by not checking the 
__get_namespace_classes function if we are not currently inside a namespace.

Either way, if we ignore namespace imports, then the best solution would 
be the following: commit Greg's patch which allows "use ::globalName", 
don't generate an error when a class is imported with the same name as 
an internal class, and modify the lookup logic so that internal classes 
are not even considered when inside a namespace. For example:

a.php
<?php
namespace ns;
$a = new Exception( 'test' ); // looks for ns::Exception
?>

b.php
<?php
$b = new Exception( 'test' ); // not inside namespace, so use 
::Exception directly
?>

The lookup rules would be:

1. Are we inside a namespace? No -> look for internal class named 
Exception. Yes -> look for ns::Exception.
2. If inside a namespace, and ns::Exception does not exist, then try 
autoloading ns::Exception.
3. If ns::Exception does not exist now, then generate an error.


The above would be consistent with how global variables are handled 
currently. In order to use a global variable inside a function, you 
first need to "import" it using a "global $name" statement. The same 
would apply here, in order to use a global/internal class, you either 
need to reference it using ::name syntax or have a "use ::name" 
statement at the beginning of the file. Since there aren't many internal 
classes in the first place, there will be few "use ::internalName" 
statements per file, so this won't burden the user.

I'll try to come up with the patch soon, incorporating Greg's "use 
::name" change.



Regards,

Jessie Hernandez
Zend Certified Engineer (http://zend.com/zce.php?c=ZEND006359&r=222727282)


Dmitry Stogov wrote:
> Hi Jessie,
> 
> The namespace may include several files and it may be extended with 
> additional files in any moment. So having single 
> __get_namespace_classes() function will require to update it every time 
> you extend namespace.
> 
> Also such function will significantly slowdown access to internal 
> classes. (It was the main reason why __autoload() was moved after check 
> for internal class).
> 
> Thanks. Dmitry.
> 
> Jessie Hernandez wrote:
> > […]
