Private class support has been completed in the attached patch! Again, to
reiterate from my last post, the attached patch is a CVS patch, as some
requested me to do. I could not add the test files to the patch because
"cvs add" failed with a "cvs add requires write access to the repository"
error (any way to fix this?).
Also, import statements now include the class files, using a new .ini
variable, "class_path". Files under the directories in the class_path have
the namespace names as directories and the class names named exactly as the
file that declares it (like Java), e.g. my_ns:class1 is declared in
$class_path/my_ns/class1.php.
Again, the only missing feature I know of is "namespace imports". I've been
thinking about it, and I think the best approach is actually very simple.
Right now, when an undefined class is found, the __autoload function is
called from zend_lookup_class to attempt to declare the class at that
point. What I propose is to modify zend_lookup_class to do an additional
lookup, either before/after the __autoload function, for namespace imported
classes. Here's an example:
<?php
import namespace my_namespace1;
// my_namespace1 is added to a runtime hashtable
import namespace my_namespace2;
// my_namespace2 is added to a runtime hashtable
$a = new class1();
?>
At compile-time, the "my_namespace1" and "my_namespace2" strings are saved
in a runtime hashtable. At runtime, zend_lookup_class will be called on
"class1", as usual. Before/after __autoload, this hashtable will be
traversed for the file "class1.php". So in the above example, an attempt to
include "$class_path/my_namespace1/class1.php" will be done. If that fails,
then my_namespace2 is tried, and so forth. If one of these attempts
succeed, then the import alias is also added to the import hashtable for
the currently-executed file, as if the user had added "import
my_namespace1:class1" to the script.
(BTW, is there a way to construct an opcode at runtime and execute it
immediately? If not, I'll have to duplicate the code I have for
ZEND_IMPORT_CLASS in another function).
I think this approach is the easiest and most sensible for namespace import
support. It is no more than a specialized "__autoload". If there are no
objections, I'll start working on it next week. As always,
comments/suggestions are most appreciated.
Regards,
Jessie Hernandez
Hello Jessie,
Wednesday, July 20, 2005, 6:05:30 AM, you wrote:
Private class support has been completed in the attached patch! Again, to
reiterate from my last post, the attached patch is a CVS patch, as some
requested me to do. I could not add the test files to the patch because
"cvs add" failed with a "cvs add requires write access to the repository"
error (any way to fix this?).
You can add the line yourself:
marcus@zaphod /usr/src/php5 $ cvs add 061.csv
cvs add: use 'cvs commit' to add this file permanently
marcus@zaphod /usr/src/php5 $ cat CVS/Entries
[...]
/061.csv/0/dummy timestamp//
Also, import statements now include the class files, using a new .ini
variable, "class_path". Files under the directories in the class_path have
the namespace names as directories and the class names named exactly as the
file that declares it (like Java), e.g. my_ns:class1 is declared in
$class_path/my_ns/class1.php.
Please don't add new ini settings here, living with include_path should be
enough, wouldn't it?
Again, the only missing feature I know of is "namespace imports". I've been
thinking about it, and I think the best approach is actually very simple.
Right now, when an undefined class is found, the __autoload function is
called from zend_lookup_class to attempt to declare the class at that
point. What I propose is to modify zend_lookup_class to do an additional
lookup, either before/after the __autoload function, for namespace imported
classes. Here's an example:
<?php
import namespace my_namespace1;
// my_namespace1 is added to a runtime hashtable
import namespace my_namespace2;
// my_namespace2 is added to a runtime hashtable
$a = new class1();
?>>
Why can't __autoload decide itself? I mean either it knows it received a
namespace class since the string contains a ':' or the function writer
has to find out himself.
At compile-time, the "my_namespace1" and "my_namespace2" strings are saved
in a runtime hashtable. At runtime, zend_lookup_class will be called on
"class1", as usual. Before/after __autoload, this hashtable will be
traversed for the file "class1.php". So in the above example, an attempt to
include "$class_path/my_namespace1/class1.php" will be done. If that fails,
then my_namespace2 is tried, and so forth. If one of these attempts
succeed, then the import alias is also added to the import hashtable for
the currently-executed file, as if the user had added "import
my_namespace1:class1" to the script.
(BTW, is there a way to construct an opcode at runtime and execute it
immediately? If not, I'll have to duplicate the code I have for
ZEND_IMPORT_CLASS in another function).
In that case you should provide a function apart the import opcode handler.
Since zend_vm_gen.h might create multiple handlers out of it this is anyway
perhaps a good idea. This function can be used of course from both handlers
and you other function.
I think this approach is the easiest and most sensible for namespace import
support. It is no more than a specialized "__autoload". If there are no
objections, I'll start working on it next week. As always,
comments/suggestions are most appreciated.
Regards,
Jessie Hernandez
--
Best regards,
Marcus mailto:mail@marcus-boerger.de
"Marcus Boerger" mail@marcus-boerger.de wrote in message
news:681697173.20050720083643@marcus-boerger.de...
Please don't add new ini settings here, living with include_path should be
enough, wouldn't it?
Do we want the import behavior to apply to the existing include path? To me,
it seems nice to have the include_path and class_path separate. The
class_path will only be used for classes, and include_path for everything
else (header/footer code, etc.). Of course, this is just my opinion. What
does everyone else think?
Why can't __autoload decide itself? I mean either it knows it received a
namespace class since the string contains a ':' or the function writer
has to find out himself.
Well, when a full namespace import is done, the string will not contain a
':'. __autoload would only receive a class name, and there is no easy way
for __autoload to know which namespace contains that class. That's why a
separate mechanism is needed from __autoload, that will look into the
class_path directories (appending the directories for the namespace name)
for the class file, and if/when found, include that. This is one other
reason why a separate class_path variable would be useful: the include_path
might have several directories, and all these would need to be searched,
even though these directories might not have classes at all. In contrast,
the directories in class_path are specifically for class files, so the
searches are faster.
--
Jessie
Hello Jessie,
Wednesday, July 20, 2005, 8:35:26 PM, you wrote:
"Marcus Boerger" mail@marcus-boerger.de wrote in message
news:681697173.20050720083643@marcus-boerger.de...Please don't add new ini settings here, living with include_path should be
enough, wouldn't it?
Do we want the import behavior to apply to the existing include path? To me,
it seems nice to have the include_path and class_path separate. The
class_path will only be used for classes, and include_path for everything
else (header/footer code, etc.). Of course, this is just my opinion. What
does everyone else think?
Why can't __autoload decide itself? I mean either it knows it received a
namespace class since the string contains a ':' or the function writer
has to find out himself.
Well, when a full namespace import is done, the string will not contain a
':'. __autoload would only receive a class name, and there is no easy way
for __autoload to know which namespace contains that class. That's why a
separate mechanism is needed from __autoload, that will look into the
class_path directories (appending the directories for the namespace name)
for the class file, and if/when found, include that. This is one other
reason why a separate class_path variable would be useful: the include_path
might have several directories, and all these would need to be searched,
even though these directories might not have classes at all. In contrast,
the directories in class_path are specifically for class files, so the
searches are faster.
might, might, might only assumptions with the big drawback of adding another
ini setting. My assumption is that i only need one or two include/class
patchs and that they are of course the same since i want to keep my
application files together - for working maintanance for one reason.
Also if __autoload cannot easily get the requested namespace name than a
compilcated solution has to be worked out since otherwise you end up in
nightmare of naming conflicts - how should you know in a situation where
a classname exists in multiple namespaces from which directory to load?
By order of directory? In the end nothing here would really work around the
problem thus we need the full name.
Best regards,
Marcus mailto:mail@marcus-boerger.de
Hello,
Well, I wouldn't use the include_path parameter of PHP for the new
namespaces lookup code, neither __autoload(). I see it as a major
language change -- the support of namespaces, where you should consider
to make all need. I suppose you want to support namespace spread over
multiple files, this shouldn't be a problem. I would only drop the
support of one class spread over multiple files for only one namespace,
nice time to raise a Fatal Error/compiler error.
You could support nameless namespaces (i.e. namespace {}) and for
backward compatibility sake dump all "float" methods in this nameless
namespace, won't cause problem. And all "new code" should just
namespaces by default, if not it will be jumped into the nameless
namespace. For example when you call a function like myNameRocks() it
should just look for the function in the nameless namespace and go with
it. Not existing? Bang! Function doesn't exist.
Enough dreaming for now, time to work again :-)
--
Yours,
Weyert de Boer (wdb@innerfuse.biz)
innerfuse*
Hello Marcus,
In my case at work, my include_path only has three directories: . (current
directory), the PEAR path, and the directory where my company's classes are
stored. In this case, the namespace import will only have to search in
three directories, which is not bad. The class_path would only save me one
directory lookup (.), so the class_path really is not needed here. Looking
again, the need for class_path really depends on whether many PHP users
have large include_paths or not. If the majority have small include_paths
(like in our cases), then I can just use include_path (my patch would be
simplified, also). Still, I'd like to gather more opinions from others.
Regarding __autoload, there is no way for __autoload to receive the full
class name without having to first scan the directories either at compile
or runtime, and of course, when I determine the full class name and path,
why call __autoload? I already know the path of the file I need to include,
so passing the class name to __autoload seems unnecessary.
For the lookup, I was thinking of searching all the directories in the
class/include_path, even if I get a match in the first directory. In the
case where there are two identically-named classes in two namespaces that
have been imported, then I will generate an error saying that the class
requested is ambiguous. The way the user would disambiguate the class name
is by entering the full class name, e.g. my_ns:class1, for that particular
class.
--
Jessie
Marcus Boerger wrote:
might, might, might only assumptions with the big drawback of adding
another ini setting. My assumption is that i only need one or two
include/class patchs and that they are of course the same since i want to
keep my application files together - for working maintanance for one
reason. Also if __autoload cannot easily get the requested namespace name
than a compilcated solution has to be worked out since otherwise you end
up in nightmare of naming conflicts - how should you know in a situation
where a classname exists in multiple namespaces from which directory to
load? By order of directory? In the end nothing here would really work
around the problem thus we need the full name.Best regards,
Marcus mailto:mail@marcus-boerger.de
My include path is huge... of course it includes the basic ones, but
also my classes path /classes/System/* , /class/System/Exceptions/* etc.
Beside of that why clutter the include_path with namespaces? In my
opinion it's something different then the rest.
p.s. you will support nameless namespaces right :+
--
Yours,
Weyert de Boer (wdb@innerfuse.biz)
innerfuse*
Hello Marcus! Thanks for the cvs add "hack", worked like a charm! I'll post
an updated patch in a few days.
--
Jessie
Marcus Boerger wrote:
Hello Jessie,
Wednesday, July 20, 2005, 6:05:30 AM, you wrote:
Private class support has been completed in the attached patch! Again, to
reiterate from my last post, the attached patch is a CVS patch, as some
requested me to do. I could not add the test files to the patch because
"cvs add" failed with a "cvs add requires write access to the repository"
error (any way to fix this?).You can add the line yourself:
marcus@zaphod /usr/src/php5 $ cvs add 061.csv
cvs add: use 'cvs commit' to add this file permanently
marcus@zaphod /usr/src/php5 $ cat CVS/Entries
[...]
/061.csv/0/dummy timestamp//Also, import statements now include the class files, using a new .ini
variable, "class_path". Files under the directories in the class_path
have the namespace names as directories and the class names named exactly
as the file that declares it (like Java), e.g. my_ns:class1 is declared
in $class_path/my_ns/class1.php.Please don't add new ini settings here, living with include_path should be
enough, wouldn't it?Again, the only missing feature I know of is "namespace imports". I've
been thinking about it, and I think the best approach is actually very
simple. Right now, when an undefined class is found, the __autoload
function is called from zend_lookup_class to attempt to declare the class
at that point. What I propose is to modify zend_lookup_class to do an
additional lookup, either before/after the __autoload function, for
namespace imported classes. Here's an example:<?php
import namespace my_namespace1;
// my_namespace1 is added to a runtime hashtable
import namespace my_namespace2;
// my_namespace2 is added to a runtime hashtable$a = new class1();
?>>Why can't __autoload decide itself? I mean either it knows it received a
namespace class since the string contains a ':' or the function writer
has to find out himself.At compile-time, the "my_namespace1" and "my_namespace2" strings are
saved in a runtime hashtable. At runtime, zend_lookup_class will be
called on "class1", as usual. Before/after __autoload, this hashtable
will be traversed for the file "class1.php". So in the above example, an
attempt to include "$class_path/my_namespace1/class1.php" will be done.
If that fails, then my_namespace2 is tried, and so forth. If one of these
attempts succeed, then the import alias is also added to the import
hashtable for the currently-executed file, as if the user had added
"import my_namespace1:class1" to the script.(BTW, is there a way to construct an opcode at runtime and execute it
immediately? If not, I'll have to duplicate the code I have for
ZEND_IMPORT_CLASS in another function).In that case you should provide a function apart the import opcode
handler. Since zend_vm_gen.h might create multiple handlers out of it this
is anyway perhaps a good idea. This function can be used of course from
both handlers and you other function.I think this approach is the easiest and most sensible for namespace
import support. It is no more than a specialized "__autoload". If there
are no objections, I'll start working on it next week. As always,
comments/suggestions are most appreciated.Regards,
Jessie Hernandez
Hi Jessie,
first, while your patch applied cleanly (except zend_vm_opcodes.h, which
is generated) the build broke with:
bison -y -p zend -v -d /mnt/home/alex/cvs/php-namespaces/Zend/zend_language_parser.y -o Zend/zend_language_parser.c
conflicts: 5 shift/reduce
/mnt/home/alex/cvs/php-namespaces/Zend/zend_language_parser.y: expected 4 shift/reduce conflicts
*** Error code 1
I had to increase the expected shift/reduce conflict count to 5 to
continue the build, which then completed successfully.
Also, import statements now include the class files, using a new .ini
variable, "class_path". Files under the directories in the class_path have
the namespace names as directories and the class names named exactly as the
file that declares it (like Java), e.g. my_ns:class1 is declared in
$class_path/my_ns/class1.php.
I don't like this idea; it restricts the developer to this Java-like
class / directory layout. It also restricts him to name his files after
the scheme you defined (which is <classname>.php) - many use other
schemes. Shouldn't PHP let you be free in this kind of decision? I think
yes, especially, as this could also be implemented with the __autoload
function in user-space.
Again, the only missing feature I know of is "namespace imports". I've been
thinking about it, and I think the best approach is actually very simple.
Here's another one: the script
<?php
$foo= 'Foo:Bar';
import $foo;
?>
gives me
alex@boost:~/cvs/php-namespaces# sapi/cli/php ~/tests/classes/dynamic_import.php
Parse error: parse error, unexpected T_VARIABLE, expecting T_NAMESPACE_NAME or T_NAMESPACE
in /mnt/home/alex/tests/classes/dynamic_import.php on line 3
(IIRC Stanislav Malyshev already mentioned this in the YANP-thread
already.)
Regards,
-Alex
Hello Alex,
Monday, July 25, 2005, 11:48:33 PM, you wrote:
Hi Jessie,
first, while your patch applied cleanly (except zend_vm_opcodes.h, which
is generated) the build broke with:
bison -y -p zend -v -d
/mnt/home/alex/cvs/php-namespaces/Zend/zend_language_parser.y -o
Zend/zend_language_parser.c
conflicts: 5 shift/reduce
/mnt/home/alex/cvs/php-namespaces/Zend/zend_language_parser.y: expected 4 shift/reduce conflicts
*** Error code 1
I had to increase the expected shift/reduce conflict count to 5 to
continue the build, which then completed successfully.
Also, import statements now include the class files, using a new .ini
variable, "class_path". Files under the directories in the class_path have
the namespace names as directories and the class names named exactly as the
file that declares it (like Java), e.g. my_ns:class1 is declared in
$class_path/my_ns/class1.php.
I don't like this idea; it restricts the developer to this Java-like
class / directory layout. It also restricts him to name his files after
the scheme you defined (which is <classname>.php) - many use other
schemes. Shouldn't PHP let you be free in this kind of decision? I think
yes, especially, as this could also be implemented with the __autoload
function in user-space.
You already have the ability to overload __autoload or provide several
userspace __autoload functions that would be called one after another
until the first succeeds. What else do you want? Besides the fact that
i am still convinced that we should find a way to pass the full namespaced
name to __autoload instead of just the classname. If you ask me not doing
so is simply an error.
Again, the only missing feature I know of is "namespace imports". I've been
thinking about it, and I think the best approach is actually very simple.
Here's another one: the script
<?php
$foo= 'Foo:Bar';
import $foo;
?>>
gives me
alex@boost:~/cvs/php-namespaces# sapi/cli/php ~/tests/classes/dynamic_import.php
Parse error: parse error, unexpected T_VARIABLE, expecting
T_NAMESPACE_NAME orT_NAMESPACE
in
/mnt/home/alex/tests/classes/dynamic_import.php on line 3
(IIRC Stanislav Malyshev already mentioned this in the YANP-thread
already.)
I don't see any reason to allow this. PHP is already far to dynamic (which
already prevents some speed improvements to the engine). Namespaces are a
means for working with several frameworks/libraries at a time and for
spreading/controlling responsibilities. In all those cases you definitively
won't need the above and its presents would circumvent what we'd achieve
here.
Best regards,
Marcus mailto:mail@marcus-boerger.de
Marcus Boerger wrote:
You already have the ability to overload __autoload or provide several
userspace __autoload functions that would be called one after another
until the first succeeds. What else do you want? Besides the fact that
i am still convinced that we should find a way to pass the full namespaced
name to __autoload instead of just the classname. If you ask me not doing
so is simply an error.
I still think that the namespace importing logic/file-naming convention is
the cleanest, but if __autoload is to be used, then I currently see three
approaches to this:
- Search in each directory in the class_path (or include_path) for
"namespace-name/class-name.php". When the first file is found, then the
full class name will be generated from that and passed on to __autoload,
e.g. if you import the my_ns namespace and use class1, then
my_ns/class1.php will be searched in the path and then __autoload will be
called with "my_ns:class1".
Requirements
- Namespace/class naming convention
Pros
- Full class name is passed to __autoload
Cons
- Performance loss (when the directories are searched, the path to the class
file is already known before __autoload is called, so generating the full
class name from the path, calling __autoload, only to then str_replace
colons with slashes and including that seems unnecessary). - When a class name exists in more than one imported namespace, the first
one found will be passed to __autoload (no way to disambiguate).
- Like (1), but search all the directories and pass an extra argument (or
pass an array or object as the first argument) to __autoload indicating the
directories where the class name was found. The first argument would be the
class name, the second argument (or an additional key in the array) would
contain the paths (or namespace names, whichever). The user would be
responsible for disambiguation in case a class exists in multiple imported
namespaces.
Requirements
- Namespace/class naming convention
Pros
- No ambiguity
- The include behavior is handled completely by the user
Cons
- In the majority of cases, a class name will not appear in more than one
namespace, so there will be a performance loss by having to search all the
directories in the class/include_path, even though there was a match on the
first directory.
- Simply pass an extra argument (or pass an array or object as the first
argument) to __autoload containing the names of the imported namespaces of
the calling file. __autoload can then use this array against the class name
and perform its own lookup.
Requirements
- None
Pros
- A namespace/class naming convention is not forced
- The include behavior/lookup is handled completely by the user
- No performance loss (all that's passed to __autoload is the class name and
an array of imported namespaces, and this is done immediately).
Cons
- IMHO, I think most users would maintain a naming convention similar to
Java's, so the user would have to add code for something which the language
should handle for them. This can be minimized, though, if a function is
added to handle this common behavior. The function can be called by the
user in __autoload and will look something like the following (of course,
the code would be in C):
<?php
function namespace_include($className, $importNamespaces)
{
$paths = explode( PATH_SEPARATOR, get_include_path()
);
foreach( $paths as $path )
{
foreach( $importNamespaces as $ns )
{
$fullPath = $path . `DIRECTORY_SEPARATOR` . str_replace( ':',
DIRECTORY_SEPARATOR, $ns ) . DIRECTORY_SEPARATOR
. $className . '.php';
if( file_exists( $fullPath ) )
{
require_once( $fullPath );
return true;
}
}
}
return false;
}
?>
I still think the namespace import behavior should be separate from the
__autoload function. Of course, this is just me. What does everyone else
think? I'd like to gather opinions on which is preferred. I will also like
to know if a separate class_path is preferred (as I have in my last patch)
or if just leaving include_path is what most prefer.
--
Jessie
Hello Jessie,
Tuesday, July 26, 2005, 5:24:02 AM, you wrote:
Marcus Boerger wrote:
You already have the ability to overload __autoload or provide several
userspace __autoload functions that would be called one after another
until the first succeeds. What else do you want? Besides the fact that
i am still convinced that we should find a way to pass the full namespaced
name to __autoload instead of just the classname. If you ask me not doing
so is simply an error.
I still think that the namespace importing logic/file-naming convention is
the cleanest, but if __autoload is to be used, then I currently see three
approaches to this:
- Search in each directory in the class_path (or include_path) for
"namespace-name/class-name.php". When the first file is found, then the
full class name will be generated from that and passed on to __autoload,
e.g. if you import the my_ns namespace and use class1, then
my_ns/class1.php will be searched in the path and then __autoload will be
called with "my_ns:class1".
Requirements
- Namespace/class naming convention
Pros
- Full class name is passed to __autoload
Cons
- Performance loss (when the directories are searched, the path to the class
file is already known before __autoload is called, so generating the full
class name from the path, calling __autoload, only to then str_replace
colons with slashes and including that seems unnecessary).- When a class name exists in more than one imported namespace, the first
one found will be passed to __autoload (no way to disambiguate).
- Like (1), but search all the directories and pass an extra argument (or
pass an array or object as the first argument) to __autoload indicating the
directories where the class name was found. The first argument would be the
class name, the second argument (or an additional key in the array) would
contain the paths (or namespace names, whichever). The user would be
responsible for disambiguation in case a class exists in multiple imported
namespaces.
Requirements
- Namespace/class naming convention
Pros
- No ambiguity
- The include behavior is handled completely by the user
Cons
- In the majority of cases, a class name will not appear in more than one
namespace, so there will be a performance loss by having to search all the
directories in the class/include_path, even though there was a match on the
first directory.
- Simply pass an extra argument (or pass an array or object as the first
argument) to __autoload containing the names of the imported namespaces of
the calling file. __autoload can then use this array against the class name
and perform its own lookup.
Requirements
- None
Pros
- A namespace/class naming convention is not forced
- The include behavior/lookup is handled completely by the user
- No performance loss (all that's passed to __autoload is the class name and
an array of imported namespaces, and this is done immediately).
Cons
- IMHO, I think most users would maintain a naming convention similar to
Java's, so the user would have to add code for something which the language
should handle for them. This can be minimized, though, if a function is
added to handle this common behavior. The function can be called by the
user in __autoload and will look something like the following (of course,
the code would be in C):
<?php
function namespace_include($className, $importNamespaces)
{
$paths = explode( PATH_SEPARATOR,get_include_path()
);
foreach( $paths as $path ) { foreach( $importNamespaces as $ns ) { $fullPath = $path . `DIRECTORY_SEPARATOR` . str_replace( ':',
DIRECTORY_SEPARATOR, $ns ) .
DIRECTORY_SEPARATOR
. $className . '.php';
if( file_exists( $fullPath ) ) { require_once( $fullPath ); return true; } } }
return false;
}
?>>
I still think the namespace import behavior should be separate from the
__autoload function. Of course, this is just me. What does everyone else
think? I'd like to gather opinions on which is preferred. I will also like
to know if a separate class_path is preferred (as I have in my last patch)
or if just leaving include_path is what most prefer.
None of the above makes any sense. Look __autoload() is just bein called at
any place where a class is missing. So looking for the file first and then
loading __autoload(I) makes no sense whatsoever. IMO what we need here is a
default implementation for import behavior accomplished by __autoload(). So
for example "import ns:cls;" leads to "__autoload('ns:cls')". Here the SPL
default implementation would relpace all ':' with the directory divider '/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file. If were are to support
import with '*' the the autoload implementation would need to take care of
this and load all matching files. A user land implementation can easily
achieve that by using SPLs (Recursive)DirectoryIterator and FilterIterator.
Best regards,
Marcus
Hi Marcus,
"Marcus Boerger" mail@marcus-boerger.de wrote in message
news:1374121835.20050726101045@marcus-boerger.de...
- Simply pass an extra argument (or pass an array or object as the
first
argument) to __autoload containing the names of the imported namespaces
of
the calling file. __autoload can then use this array against the class
name
and perform its own lookup.None of the above makes any sense. Look __autoload() is just bein called
at
any place where a class is missing. So looking for the file first and then
loading __autoload(I) makes no sense whatsoever. IMO what we need here is
a
default implementation for import behavior accomplished by __autoload().
So
for example "import ns:cls;" leads to "__autoload('ns:cls')". Here the SPL
default implementation would relpace all ':' with the directory divider
'/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file. If were are to
support
import with '*' the the autoload implementation would need to take care of
this and load all matching files. A user land implementation can easily
achieve that by using SPLs (Recursive)DirectoryIterator and
FilterIterator.
Regarding a fully-specified class import, such as ns:cls, if I simply remove
my include logic, then __autoload('ns:cls') would automatically be called.
There are no issues with this type of import.
Now, namespace imports (wildcard imports) are a different story. Maybe I did
not make my explanations clear enough, but you basically agreed to point #3
in my previous email. Now, the class name cannot simply be passed to
__autoload, because there is no way for __autoload to know to which
namespace the class belongs to, and you only want __autoload to include the
classes belonging to the namespaces that have been imported. That is why the
list of imported namespaces for the calling file must be accessible
somehow to the __autoload function, either as an additional argument or by
having the first argument be an array/object.
So the namespace imports will work like how you described simple imports,
but with a slight twist. To quote you:
"Simple" Imports
So for example "import ns:cls;" leads to "__autoload('ns:cls')". Here the
SPL
default implementation would relpace all ':' with the directory divider
'/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file.
By slightly modifying your sentence, we implement namespace imports:
Namespace Imports
Here the SPL default implementation would, in a loop, prefix the class name
with each imported namespace, replace all ':' with the directory divider '/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file.
For example, here is how the userland __autoload might look (notice that
this code is exactly what I provided in the last post). In this example, the
user has the directory structure as "namespace-name/class-name.php".
<?php
function __autoload($className, $importNamespaces)
{
$paths = explode( PATH_SEPARATOR, get_include_path()
);
foreach( $paths as $path )
{
foreach( $importNamespaces as $ns )
{
$fullPath = $path . `DIRECTORY_SEPARATOR` . str_replace( ':',
DIRECTORY_SEPARATOR, $ns ) . DIRECTORY_SEPARATOR
. $className . '.php';
if( file_exists( $fullPath ) )
{
require_once( $fullPath );
break;
}
}
}
}
?>
Let me know if the above make sense or if you see any problems with this
approach.
--
Jessie
Hello Jessie,
Tuesday, July 26, 2005, 5:50:35 PM, you wrote:
Hi Marcus,
"Marcus Boerger" mail@marcus-boerger.de wrote in message
news:1374121835.20050726101045@marcus-boerger.de...
- Simply pass an extra argument (or pass an array or object as the
first
argument) to __autoload containing the names of the imported namespaces
of
the calling file. __autoload can then use this array against the class
name
and perform its own lookup.None of the above makes any sense. Look __autoload() is just bein called
at
any place where a class is missing. So looking for the file first and then
loading __autoload(I) makes no sense whatsoever. IMO what we need here is
a
default implementation for import behavior accomplished by __autoload().
So
for example "import ns:cls;" leads to "__autoload('ns:cls')". Here the SPL
default implementation would relpace all ':' with the directory divider
'/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file. If were are to
support
import with '*' the the autoload implementation would need to take care of
this and load all matching files. A user land implementation can easily
achieve that by using SPLs (Recursive)DirectoryIterator and
FilterIterator.
Regarding a fully-specified class import, such as ns:cls, if I simply remove
my include logic, then __autoload('ns:cls') would automatically be called.
There are no issues with this type of import.
Now, namespace imports (wildcard imports) are a different story. Maybe I did
not make my explanations clear enough, but you basically agreed to point #3
in my previous email. Now, the class name cannot simply be passed to
__autoload, because there is no way for __autoload to know to which
namespace the class belongs to, and you only want __autoload to include the
classes belonging to the namespaces that have been imported. That is why the
list of imported namespaces for the calling file must be accessible
somehow to the __autoload function, either as an additional argument or by
having the first argument be an array/object.
So the namespace imports will work like how you described simple imports,
but with a slight twist. To quote you:
"Simple" Imports
So for example "import ns:cls;" leads to "__autoload('ns:cls')". Here the
SPL
default implementation would relpace all ':' with the directory divider
'/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file.
By slightly modifying your sentence, we implement namespace imports:
Namespace Imports
Here the SPL default implementation would, in a loop, prefix the class name
with each imported namespace, replace all ':' with the directory divider '/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file.
For example, here is how the userland __autoload might look (notice that
this code is exactly what I provided in the last post). In this example, the
user has the directory structure as "namespace-name/class-name.php".
<?php
function __autoload($className, $importNamespaces)
{
$paths = explode( PATH_SEPARATOR,get_include_path()
);
foreach( $paths as $path ) { foreach( $importNamespaces as $ns ) { $fullPath = $path . `DIRECTORY_SEPARATOR` . str_replace( ':',
DIRECTORY_SEPARATOR, $ns ) .
DIRECTORY_SEPARATOR
. $className . '.php';
if( file_exists( $fullPath ) ) { require_once( $fullPath ); break; } } }
}
?>>
Let me know if the above make sense or if you see any problems with this
approach.
On a first sight i only see that 'break' should be 'return'.
Best regards,
Marcus
Yes, you are correct, 'break' should be 'return'.
--
Jessie
"Marcus Boerger" helly@php.net wrote in message
news:1531018265.20050726203858@marcus-boerger.de...
On a first sight i only see that 'break' should be 'return'.
Best regards,
Marcus
I still think the namespace import behavior should be separate from the
__autoload function. Of course, this is just me. What does everyone else
think? I'd like to gather opinions on which is preferred. I will also like
to know if a separate class_path is preferred (as I have in my last patch)
or if just leaving include_path is what most prefer.None of the above makes any sense. Look __autoload() is just bein called at
any place where a class is missing. So looking for the file first and then
loading __autoload(I) makes no sense whatsoever. IMO what we need here is a
default implementation for import behavior accomplished by __autoload(). So
for example "import ns:cls;" leads to "__autoload('ns:cls')". Here the SPL
default implementation would relpace all ':' with the directory divider '/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file. If were are to support
import with '*' the the autoload implementation would need to take care of
this and load all matching files. A user land implementation can easily
achieve that by using SPLs (Recursive)DirectoryIterator and FilterIterator.
What are the options when having a PHP without SPL, then? That
__autoload invocation chain once in discussion hasn't yet been
implemented, right?
Regards,
-Alex
Hello Alex,
Tuesday, July 26, 2005, 11:54:02 PM, you wrote:
I still think the namespace import behavior should be separate from the
__autoload function. Of course, this is just me. What does everyone else
think? I'd like to gather opinions on which is preferred. I will also like
to know if a separate class_path is preferred (as I have in my last patch)
or if just leaving include_path is what most prefer.None of the above makes any sense. Look __autoload() is just bein called at
any place where a class is missing. So looking for the file first and then
loading __autoload(I) makes no sense whatsoever. IMO what we need here is a
default implementation for import behavior accomplished by __autoload(). So
for example "import ns:cls;" leads to "__autoload('ns:cls')". Here the SPL
default implementation would relpace all ':' with the directory divider '/'
or '', append '.inc' or '.php' or '.inc.php' and append the result to all
directories in the include_path to look for the file. If were are to support
import with '*' the the autoload implementation would need to take care of
this and load all matching files. A user land implementation can easily
achieve that by using SPLs (Recursive)DirectoryIterator and FilterIterator.
What are the options when having a PHP without SPL, then? That
__autoload invocation chain once in discussion hasn't yet been
implemented, right?
The only differences would be that there won't be a fallback and that you
won't be able to have more than one __autoload function. And SPL's
implemenetation is that chain.
Best regards,
Marcus
I don't like this idea; it restricts the developer to this Java-like
class / directory layout. It also restricts him to name his files after
the scheme you defined (which is <classname>.php) - many use other
schemes. Shouldn't PHP let you be free in this kind of decision? I think
yes, especially, as this could also be implemented with the __autoload
function in user-space.You already have the ability to overload __autoload or provide several
userspace __autoload functions that would be called one after another
until the first succeeds. What else do you want? Besides the fact that
i am still convinced that we should find a way to pass the full namespaced
name to __autoload instead of just the classname. If you ask me not doing
so is simply an error.
Yes, I was saying to use __autoload instead of the proposed import
magic.
Here's another one: the script
<?php
$foo= 'Foo:Bar';
import $foo;
?>>gives me
alex@boost:~/cvs/php-namespaces# sapi/cli/php ~/tests/classes/dynamic_import.php
Parse error: parse error, unexpected T_VARIABLE, expecting
T_NAMESPACE_NAME orT_NAMESPACE
in
/mnt/home/alex/tests/classes/dynamic_import.php on line 3(IIRC Stanislav Malyshev already mentioned this in the YANP-thread
already.)I don't see any reason to allow this. PHP is already far to dynamic (which
already prevents some speed improvements to the engine). Namespaces are a
means for working with several frameworks/libraries at a time and for
spreading/controlling responsibilities. In all those cases you definitively
won't need the above and its presents would circumvent what we'd achieve
here.
import $this is just something I'd expect PHP to be able to deal with -
but I could live without it.
Btw, if you're saying "Namespaces are for spreading/controlling
responsibilities", do you mean something like the package access level
for methods and member variables Java has? Is anyone thinking of
introducing this?
-Alex
Hello Alex,
"Alex Kiesel" alex@kiesel.name wrote in message
news:1122412467.4938.7.camel@boost.home.ahk...
import $this is just something I'd expect PHP to be able to deal with -
but I could live without it.
I never meant to implement this, and I also agree with Marcus that there's
no reason to allow it.
Btw, if you're saying "Namespaces are for spreading/controlling
responsibilities", do you mean something like the package access level
for methods and member variables Java has? Is anyone thinking of
introducing this?
Could you please clarify what you're referring to here? If you are talking
about "package scope" for classes, this is already present in my patch. When
inside a namespace, if you declare a class as "private class my_class", then
that class will only be accessible from that namespace (even if the classes
are spread out in several files, as long as they're in the same namespace,
those classes can use the private class). Right now, I'm enforcing this by
checking that the classes are both in the same directory. Once I finish my
__autoload change, I'll have to instead check the namespace "prefixes" on
both class names to allow flexibility.
--
Jessie
Alex Kiesel wrote:
Hi Jessie,
first, while your patch applied cleanly (except zend_vm_opcodes.h, which
is generated) the build broke with:
bison -y -p zend -v -d
/mnt/home/alex/cvs/php-namespaces/Zend/zend_language_parser.y -o
Zend/zend_language_parser.c
conflicts: 5 shift/reduce
/mnt/home/alex/cvs/php-namespaces/Zend/zend_language_parser.y: expected 4
shift/reduce conflicts *** Error code 1I had to increase the expected shift/reduce conflict count to 5 to
continue the build, which then completed successfully.
I am no expert in bison or yacc, so could someone look at the patch and tell
me what, if anything, is wrong, and how to fix it?
I don't like this idea; it restricts the developer to this Java-like
class / directory layout. It also restricts him to name his files after
the scheme you defined (which is <classname>.php) - many use other
schemes. Shouldn't PHP let you be free in this kind of decision? I think
yes, especially, as this could also be implemented with the __autoload
function in user-space.
The scheme is needed in order to locate class files for the classes that
have been imported in a full namespace import. With no convention, we're
forced to call __autoload, and since the only thing that will be passed is
the class name, __autoload will have no way of knowing to what namespace
that class belongs to. With the convention, each imported namespace's
directory can be checked to see which one contains the class file.
Here's another one: the script
<?php
$foo= 'Foo:Bar';
import $foo;
?>gives me
alex@boost:~/cvs/php-namespaces# sapi/cli/php
~/tests/classes/dynamic_import.phpParse error: parse error, unexpected T_VARIABLE, expecting
T_NAMESPACE_NAME orT_NAMESPACE
in
/mnt/home/alex/tests/classes/dynamic_import.php on line 3(IIRC Stanislav Malyshev already mentioned this in the YANP-thread
already.)
What Stanislav and I were discussing was not this, it was the following
(variable class names), which is fully supported in the patch:
<?php
import Foo:Bar;
$name = 'Bar';
$obj = new $name();
?>
Anyways, thanks for taking the time to try out the patch! Let me know if you
have any other ideas/suggestions.
--
Jessie
Hello Jessie,
i am quite sure it tells you that you have a conflict with the ternary
operator. Look up the archives on the issue. There should also be an
example on the matter.
marcus
Tuesday, July 26, 2005, 2:02:56 AM, you wrote:
Alex Kiesel wrote:
Hi Jessie,
first, while your patch applied cleanly (except zend_vm_opcodes.h, which
is generated) the build broke with:
bison -y -p zend -v -d
/mnt/home/alex/cvs/php-namespaces/Zend/zend_language_parser.y -o
Zend/zend_language_parser.c
conflicts: 5 shift/reduce
/mnt/home/alex/cvs/php-namespaces/Zend/zend_language_parser.y: expected 4
shift/reduce conflicts *** Error code 1I had to increase the expected shift/reduce conflict count to 5 to
continue the build, which then completed successfully.
I am no expert in bison or yacc, so could someone look at the patch and tell
me what, if anything, is wrong, and how to fix it?
I don't like this idea; it restricts the developer to this Java-like
class / directory layout. It also restricts him to name his files after
the scheme you defined (which is <classname>.php) - many use other
schemes. Shouldn't PHP let you be free in this kind of decision? I think
yes, especially, as this could also be implemented with the __autoload
function in user-space.
The scheme is needed in order to locate class files for the classes that
have been imported in a full namespace import. With no convention, we're
forced to call __autoload, and since the only thing that will be passed is
the class name, __autoload will have no way of knowing to what namespace
that class belongs to. With the convention, each imported namespace's
directory can be checked to see which one contains the class file.
Here's another one: the script
<?php
$foo= 'Foo:Bar';
import $foo;
?>gives me
alex@boost:~/cvs/php-namespaces# sapi/cli/php
~/tests/classes/dynamic_import.phpParse error: parse error, unexpected T_VARIABLE, expecting
T_NAMESPACE_NAME orT_NAMESPACE
in
/mnt/home/alex/tests/classes/dynamic_import.php on line 3(IIRC Stanislav Malyshev already mentioned this in the YANP-thread
already.)
What Stanislav and I were discussing was not this, it was the following
(variable class names), which is fully supported in the patch:
<?php
import Foo:Bar;
$name = 'Bar';
$obj = new $name();
?>>
Anyways, thanks for taking the time to try out the patch! Let me know if you
have any other ideas/suggestions.
--
Jessie
--
Best regards,
Marcus mailto:mail@marcus-boerger.de
Hello,
How can I use the namespaces support, in such way that I can use with my
coding guideline?
interfaces -> interface.NAME.inc.php
classes -> class.NAME.inc.php
It doesn't seem it's possible now, because it's hard coded against
NAME.php. Oh well, I might will have
a look at it, and try to come with some workable, with support for
nameless namespaces, etc.
--
Yours,
Weyert de Boer (wdb@innerfuse.biz)
innerfuse*
Hello Weyert,
Tuesday, July 26, 2005, 10:04:28 AM, you wrote:
Hello,
How can I use the namespaces support, in such way that I can use with my
coding guideline?
interfaces -> interface.NAME.inc.php
classes -> class.NAME.inc.php
It doesn't seem it's possible now, because it's hard coded against
NAME.php. Oh well, I might will have
a look at it, and try to come with some workable, with support for
nameless namespaces, etc.
I have the same probelm and don't see any reason in a hard coded
naming scheme unless be it a default fallback. Look at my other
reply.
Best regards,
Marcus
Hello,
May I make some sort of suggestion, without having a closer look at the
internal working of PHP, the below is jsut one big day dream for me.
My idea is to wrap namespaces by default, for example when you aren't
using any namespace-keywords into your code, the parser will add these
accordingly to a nameless namespace (i.e.: namespace { }) this means
that you can access a class just as normal via MyClassName() etc. But
when you are using namespaces i..e
namespace innerfuse {
namespace RepositoryEngine {
final interface IRepistory {
blabla
}
class Repository implements IRepository {
// blabla
}
}
}
You can now access those stuff via innerfuse.;
innerfuse.RepositoryEngine. or the exact "path" to the class or
interface innerfuse.RepositoryEngine.*. Now probably will ask but how do
you want to lookup the class files? Well, I think this can be done
through by defining a classPath. I won't mind putting my files which use
namespaces in a specified directory, as long this can be altered i.e.
set_classes_path( 'blabla' ) or through comments magic.
Now because each PHP file needs to be parsed anyway before it can be
used, i.e. transformation to opcode. You can of course just get all the
php files, from the classes path recursively. Keep a list of all
namespaces found and classes which belong to these in a hierarchy, for
example you could give each class a unique number/name internally.
After all the available classes and namespaces are available, or when a
namespace confliction is encountered, a fatal error should be raised.
You now got a nice tree of available classes and to which namespaces it
belongs, with a reference to the file where the class definition is
available. Now you won't need this file anymore, though. It should now
be possible to convert it into the opcode.
Anyways some sort of caching is always nice, for example a hidden file
myphpfile.php.cache which includes a cached version of the php file in
opcode, which same some parsing time :+
Still thinking in progress, lunch time now ;-)
--
Yours,
Weyert de Boer (wdb@innerfuse.biz)
innerfuse*
I will work on a little proof of concept, thingy to see I can make this
work.
Hopefully I have something nice to show in a while, hope guys won't have
serious
problems when I use the current lexer etc.?
--
Yours,
Weyert de Boer (wdb@innerfuse.biz)
innerfuse*
Hello Weyert,
"Weyert de Boer" wdb@innerfuse.biz wrote in message
news:42E5FCE1.10706@innerfuse.biz...
Hello,
May I make some sort of suggestion, without having a closer look at the
internal working of PHP, the below is jsut one big day dream for me.My idea is to wrap namespaces by default, for example when you aren't
using any namespace-keywords into your code, the parser will add these
accordingly to a nameless namespace (i.e.: namespace { }) this means
that you can access a class just as normal via MyClassName() etc.
This already works in the current patch. If the class does not reside in a
namespace, then it belongs to the "global" namespace and it is left
unprefixed in the class_table. What you describe as "nameless namespace" is
what the global namespace is. Your syntax for "nameless namespaces" also
means something different in C++, which are "anonymous namespaces".
Anonymous namespaces can be used to declare classes in one file for use only
within the file in which it was declared (if the class is referenced from
another file, an error will be generated). I can easily add this feature in
my implementation. Does anyone find this feature useful?
But when you are using namespaces i..e
namespace innerfuse {
namespace RepositoryEngine { final interface IRepistory { blabla } class Repository implements IRepository { // blabla } }
}
You can now access those stuff via innerfuse.;
innerfuse.RepositoryEngine. or the exact "path" to the class or
interface innerfuse.RepositoryEngine.*. Now probably will ask but how do
you want to lookup the class files? Well, I think this can be done
through by defining a classPath. I won't mind putting my files which use
namespaces in a specified directory, as long this can be altered i.e.
set_classes_path( 'blabla' ) or through comments magic.
Since __autoload will now be used, the class_path .ini variable seems
unnecessary.
Now because each PHP file needs to be parsed anyway before it can be
used, i.e. transformation to opcode. You can of course just get all the
php files, from the classes path recursively. Keep a list of all
namespaces found and classes which belong to these in a hierarchy, for
example you could give each class a unique number/name internally.
After all the available classes and namespaces are available, or when a
namespace confliction is encountered, a fatal error should be raised.
You now got a nice tree of available classes and to which namespaces it
belongs, with a reference to the file where the class definition is
available. Now you won't need this file anymore, though. It should now
be possible to convert it into the opcode.
Recursively reading/parsing each file under the class_path would be VERY
slow to say the least. Caching would be an absolute requirement. Regarding
this...
Anyways some sort of caching is always nice, for example a hidden file
myphpfile.php.cache which includes a cached version of the php file in
opcode, which same some parsing time :+
Let's say all the classes have been searched and cached in the .cache file,
and that later I add a new class to the class_path and create a new script
that uses this new class. How will I know that a new file has been added to
a directory under the class_path? I would have to recursively go through the
directories again to see if the new class is defined there. Also, if I
change the name of a class in a file that has already been cached in the
.cache file, I will not be notified of this change either.
I also see locking issues with this approach. If multiple requests are being
performed and the .cache file does not exist yet, the other requests somehow
have to be notified to wait until the first request goes through all of the
files in the class_path and creates the .cache file. This is another big
performance issue.
--
Jessie
"Marcus Boerger" mail@marcus-boerger.de wrote in message
news:03165207.20050726101137@marcus-boerger.de...
Hello Weyert,
Tuesday, July 26, 2005, 10:04:28 AM, you wrote:
Hello,
How can I use the namespaces support, in such way that I can use with my
coding guideline?interfaces -> interface.NAME.inc.php
classes -> class.NAME.inc.phpIt doesn't seem it's possible now, because it's hard coded against
NAME.php. Oh well, I might will have
a look at it, and try to come with some workable, with support for
nameless namespaces, etc.I have the same probelm and don't see any reason in a hard coded
naming scheme unless be it a default fallback. Look at my other
reply.Best regards,
Marcus
Based on what I see above, there appears to be several users which do not
follow the PEAR file naming convention for their own classes. In order to
have flexibility in this area, we are forced to let __autoload handle the
include logic. I will post a patch in a few days with this change (as a
result, my patch will be much smaller). I will also add the namespace import
logic as described in my other post. Basically, the user will be responsible
for all importing behavior in __autoload.
In order for namespace imports to work correctly, an additional parameter
needs to be passed to __autoload that will contain an array of imported
namespaces from the file that triggered the __autoload call. Does anyone see
any problems with this additional argument? This argument would only be
passed if the class name does not contain a colon (meaning that the class
could possibly reside under one of these namespaces).
--
Jessie
Hello Jessie,
Tuesday, July 26, 2005, 8:59:55 PM, you wrote:
"Marcus Boerger" mail@marcus-boerger.de wrote in message
news:03165207.20050726101137@marcus-boerger.de...Hello Weyert,
Tuesday, July 26, 2005, 10:04:28 AM, you wrote:
Hello,
How can I use the namespaces support, in such way that I can use with my
coding guideline?interfaces -> interface.NAME.inc.php
classes -> class.NAME.inc.phpIt doesn't seem it's possible now, because it's hard coded against
NAME.php. Oh well, I might will have
a look at it, and try to come with some workable, with support for
nameless namespaces, etc.I have the same probelm and don't see any reason in a hard coded
naming scheme unless be it a default fallback. Look at my other
reply.Best regards,
Marcus
Based on what I see above, there appears to be several users which do not
follow the PEAR file naming convention for their own classes. In order to
have flexibility in this area, we are forced to let __autoload handle the
include logic. I will post a patch in a few days with this change (as a
result, my patch will be much smaller). I will also add the namespace import
logic as described in my other post. Basically, the user will be responsible
for all importing behavior in __autoload.
In order for namespace imports to work correctly, an additional parameter
needs to be passed to __autoload that will contain an array of imported
namespaces from the file that triggered the __autoload call. Does anyone see
any problems with this additional argument? This argument would only be
passed if the class name does not contain a colon (meaning that the class
could possibly reside under one of these namespaces).
Yes you cannot simply change signatures of internal functions. And also you
don't need to since you can easily provide a helper function(s) or you can
give direct access to the list itself.
Best regards,
Marcus