[PATCH] Namespace Patch, Alpha 3

php.internals

Jessie Hernandez

21 years ago
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

Marcus Boerger

21 years ago
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

Jessie Hernandez

21 years ago
"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

Marcus Boerger

21 years ago
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

Weyert de Boer

21 years ago
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* http://www.innerfuse.biz/

Jessie Hernandez

21 years ago
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:

Weyert de Boer

21 years ago
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* http://www.innerfuse.biz/

Jessie Hernandez

21 years ago
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:

Alex Kiesel

21 years ago
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. On Wed, 2005-07-20 at 00:05 -0400, Jessie Hernandez wrote:
> 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

Marcus Boerger

21 years ago
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.
> On Wed, 2005-07-20 at 00:05 -0400, Jessie Hernandez wrote: >> 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 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.)
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

Jessie Hernandez

21 years ago
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: 1) 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). 2) 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. 3) 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

Marcus Boerger

21 years ago
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:
> 1) 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).
> 2) 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.
> 3) 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

Jessie Hernandez

21 years ago
Hi Marcus, "Marcus Boerger" <mail@marcus-boerger.de> wrote in message news:1374121835.20050726101045@marcus-boerger.de...
> > > 3) 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

Marcus Börger

21 years ago
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... >> >> > 3) 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

Jessie Hernandez

21 years ago
Yes, you are correct, 'break' should be 'return'.
-- Jessie "Marcus Boerger" <helly@php.net> wrote in message news:1531018265.20050726203858@marcus-boerger.de...

Alex Kiesel

21 years ago
On Tue, 2005-07-26 at 10:10 +0200, Marcus Boerger 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? Regards, -Alex

Marcus Börger

21 years ago
Hello Alex, Tuesday, July 26, 2005, 11:54:02 PM, you wrote:
> On Tue, 2005-07-26 at 10:10 +0200, Marcus Boerger 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

Alex Kiesel

21 years ago
On Mon, 2005-07-25 at 23:59 +0200, Marcus Boerger wrote:
> > 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 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.) > > 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

Jessie Hernandez

21 years ago
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

Jessie Hernandez

21 years ago
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 1 > > I 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.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.) >
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

Marcus Boerger

21 years ago
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 1 >> >> I 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.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.) >>
> 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

Weyert de Boer

21 years ago
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* http://www.innerfuse.biz/

Marcus Boerger

21 years ago
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

Weyert de Boer

21 years ago
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* http://www.innerfuse.biz/

Weyert de Boer

21 years ago
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* http://www.innerfuse.biz/

Jessie Hernandez

21 years ago
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

Jessie Hernandez

21 years ago
"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.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
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

Marcus Börger

21 years ago
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.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
> 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